changeset 2656:12b1a2662939

Remove Storage service and most of the Statement API code review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/023145.html reviewed-by: ebaron
author Mario Torre <neugens.limasoftware@gmail.com>
date Fri, 19 May 2017 11:58:05 +0200
parents 6d9c3f8c910f
children 209c6fbeab9c
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java distribution/pom.xml launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java plugins/pom.xml plugins/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/Activator.java plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmTlabStatDAOImpl.java plugins/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/ActivatorTest.java storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Add.java storage/core/src/main/java/com/redhat/thermostat/storage/core/AggregateQuery.java storage/core/src/main/java/com/redhat/thermostat/storage/core/BackingStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/core/DbService.java storage/core/src/main/java/com/redhat/thermostat/storage/core/DbServiceFactory.java storage/core/src/main/java/com/redhat/thermostat/storage/core/HostBoundaryPojoGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/HostTimeIntervalPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/ParsedStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementFactory.java storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementSetter.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/Remove.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Replace.java storage/core/src/main/java/com/redhat/thermostat/storage/core/SecureQueuedStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/SecureStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Statement.java storage/core/src/main/java/com/redhat/thermostat/storage/core/StatementDescriptor.java storage/core/src/main/java/com/redhat/thermostat/storage/core/StatementExecutionException.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/StorageProvider.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDao.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoOperation.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoOperationResult.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoQuery.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/BaseCountable.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/DaoOperation.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/DaoQuery.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/DaoStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/QueryResult.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/SimpleDaoQuery.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/SimpleDaoStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/StatementResult.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/CountingDecorator.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/DbServiceImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/LoggingUtil.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/AbstractUnfinished.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/BasicDescriptorParser.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/BinaryExpressionNode.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/LimitExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Node.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/NotBooleanExpressionNode.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Operator.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Patchable.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedSetListMember.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedSortMember.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedWhereExpressionImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Printable.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SemanticsEnabledDescriptorParser.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SetList.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SetListValue.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortMember.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SuffixExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/TerminalNode.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnaryExpressionNode.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Unfinished.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedLimitValue.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedSortKey.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedValueNode.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/WhereExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryComparisonExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryComparisonOperator.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryLogicalExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryLogicalOperator.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryOperator.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinarySetMembershipExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/BinarySetMembershipOperator.java storage/core/src/main/java/com/redhat/thermostat/storage/query/ComparisonExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/Expression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/ExpressionFactory.java storage/core/src/main/java/com/redhat/thermostat/storage/query/LiteralExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/LiteralSetExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/LogicalExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/Operator.java storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryLogicalExpression.java storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryLogicalOperator.java storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryOperator.java storage/core/src/test/java/com/redhat/thermostat/storage/core/AggregateQueryTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/HostBoundaryPojoGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/PreparedParamentersTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/StatementDescriptorTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoOperationResultTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoOperationTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoQueryTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoStatementTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/BaseCountableTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/QueryResultTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/SimpleDaoQueryTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/SimpleDaoStatementTest.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/StatementResultTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/DbServiceImplTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/BasicDescriptorParserTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/DescriptorParserImplFactory.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/LimitExpressionTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImplTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParserType.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImplTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SemanticsEnabledDescriptorParserTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SetListValueTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SortMemberTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorTester.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/TerminalNodeTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/TestParser.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressions.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressionsTest.java storage/core/src/test/java/com/redhat/thermostat/storage/query/BinaryExpressionTest.java storage/core/src/test/java/com/redhat/thermostat/storage/query/ExpressionFactoryTest.java storage/core/src/test/java/com/redhat/thermostat/storage/query/LiteralExpressionTest.java storage/core/src/test/java/com/redhat/thermostat/storage/query/LiteralSetExpressionTest.java storage/core/src/test/java/com/redhat/thermostat/storage/query/UnaryExpressionTest.java storage/pom.xml storage/testutils/pom.xml storage/testutils/src/main/java/com/redhat/thermostat/storage/internal/statement/DescriptorParserImplFactory.java storage/testutils/src/main/java/com/redhat/thermostat/storage/internal/statement/TestParser.java storage/testutils/src/main/java/com/redhat/thermostat/storage/testutils/ParserType.java storage/testutils/src/main/java/com/redhat/thermostat/storage/testutils/StatementDescriptorTester.java storage/testutils/src/main/java/com/redhat/thermostat/storage/testutils/package-info.java storage/testutils/src/test/java/com/redhat/thermostat/storage/testutils/StatementDescriptorTesterTest.java
diffstat 154 files changed, 40 insertions(+), 19170 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java	Fri May 19 11:37:45 2017 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java	Fri May 19 11:58:05 2017 +0200
@@ -292,7 +292,7 @@
             public void dependenciesUnavailable() {
                 if (shutdownLatch.getCount() > 0) {
                     // In the rare case we lose one of our deps, gracefully shutdown
-                    logger.severe("Storage unexpectedly became unavailable");
+                    logger.severe("Dependencies unexpectedly became unavailable");
                     shutdown(ExitStatus.EXIT_ERROR);
                 }
             }
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java	Fri May 19 11:37:45 2017 +0200
+++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java	Fri May 19 11:58:05 2017 +0200
@@ -50,12 +50,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.apache.commons.codec.binary.Base64;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-
-
 import com.redhat.thermostat.agent.command.ConfigurationServer;
 import com.redhat.thermostat.agent.command.ReceiverRegistry;
 import com.redhat.thermostat.agent.command.RequestReceiver;
@@ -69,9 +63,6 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 import com.redhat.thermostat.shared.config.OS;
-import com.redhat.thermostat.storage.core.AuthToken;
-import com.redhat.thermostat.storage.core.SecureStorage;
-import com.redhat.thermostat.storage.core.Storage;
 
 class CommandChannelDelegate implements ConfigurationServer, ThermostatIPCCallbacks {
     
@@ -87,7 +78,6 @@
     
     private final ReceiverRegistry receivers;
     private final SSLConfiguration sslConf;
-    private final StorageGetter storageGetter;
     private final File binPath;
     private final AgentIPCService ipcService;
     private final CountDownLatch readyLatch;
@@ -103,16 +93,15 @@
     CommandChannelDelegate(ReceiverRegistry receivers, SSLConfiguration sslConf, File binPath,
             AgentIPCService ipcService) {
         this(receivers, sslConf, binPath, ipcService, new CountDownLatch(1), new SSLConfigurationEncoder(), 
-                new AgentRequestDecoder(), new AgentResponseEncoder(), new StorageGetter(), new ProcessUserInfoBuilder(), 
+                new AgentRequestDecoder(), new AgentResponseEncoder(), new ProcessUserInfoBuilder(),
                 new FileSystemUtils(), new ProcessCreator());
     }
 
     /** For testing only */
     CommandChannelDelegate(ReceiverRegistry receivers, SSLConfiguration sslConf, File binPath, 
             AgentIPCService ipcService, CountDownLatch readyLatch, SSLConfigurationEncoder sslEncoder, 
-            AgentRequestDecoder requestDecoder, AgentResponseEncoder responseEncoder, StorageGetter getter, 
+            AgentRequestDecoder requestDecoder, AgentResponseEncoder responseEncoder,
             ProcessUserInfoBuilder userInfoBuilder, FileSystemUtils fsUtils, ProcessCreator procCreator) {
-        this.storageGetter = getter;
         this.receivers = receivers;
         this.sslConf = sslConf;
         this.binPath = binPath;
@@ -302,37 +291,12 @@
     }
 
     private boolean authenticateRequestIfNecessary(Request request) {
-        Storage storage = storageGetter.get();
-        boolean result = false;
-        if (storage instanceof SecureStorage) {
-            result = authenticateRequest(request, (SecureStorage) storage);
-            if (result) {
-                logger.finest("Authentication and authorization for request " + request + " succeeded!");
-            } else {
-                logger.finest("Request " + request + " failed to authenticate or authorize");
-            }
-        } else {
-            result = true;
-        }
-        storageGetter.unget();
-        return result;
-    }
-
-    private boolean authenticateRequest(Request request, SecureStorage storage) {
-        String clientTokenStr = request.getParameter(Request.CLIENT_TOKEN);
-        byte[] clientToken = Base64.decodeBase64(clientTokenStr);
-        String authTokenStr = request.getParameter(Request.AUTH_TOKEN);
-        byte[] authToken = Base64.decodeBase64(authTokenStr);
-        AuthToken token = new AuthToken(authToken, clientToken);
-        String actionName = request.getParameter(Request.ACTION);
-        try {
-            // actionName must not be null here. If we somehow get a bogus request
-            // at this point where this does not exist, verifyToken will throw a
-            // NPE.
-            return storage.verifyToken(token, actionName);
-        } catch (NullPointerException e) {
-            return false; 
-        }
+        /*
+         * FIXME Authentication no longer works after the introduction of the
+         * web gateway. For now, we bypass authentication until the new
+         * WebSockets command channel is integrated.
+         */
+        return true;
     }
 
     private boolean checkStart(byte[] data) {
@@ -361,22 +325,6 @@
     }
 
     /** for testing only */
-    static class StorageGetter {
-        Storage get() {
-            BundleContext bCtx = FrameworkUtil.getBundle(getClass()).getBundleContext();
-            ServiceReference<Storage> storageRef = bCtx.getServiceReference(Storage.class);
-            Storage storage = (Storage) bCtx.getService(storageRef);
-            return storage;
-        }
-        
-        void unget() {
-            BundleContext bCtx = FrameworkUtil.getBundle(getClass()).getBundleContext();
-            ServiceReference<Storage> storageRef = bCtx.getServiceReference(Storage.class);
-            bCtx.ungetService(storageRef);
-        }
-    }
-    
-    /** for testing only */
     static class ProcessCreator {
         Process startProcess(ProcessBuilder builder) throws IOException {
             return builder.start();
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java	Fri May 19 11:37:45 2017 +0200
+++ b/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java	Fri May 19 11:58:05 2017 +0200
@@ -58,7 +58,6 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
-import org.apache.commons.codec.binary.Base64;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -69,7 +68,6 @@
 import com.redhat.thermostat.agent.command.RequestReceiver;
 import com.redhat.thermostat.agent.command.internal.CommandChannelDelegate.FileSystemUtils;
 import com.redhat.thermostat.agent.command.internal.CommandChannelDelegate.ProcessCreator;
-import com.redhat.thermostat.agent.command.internal.CommandChannelDelegate.StorageGetter;
 import com.redhat.thermostat.agent.ipc.server.AgentIPCService;
 import com.redhat.thermostat.agent.ipc.server.IPCMessage;
 import com.redhat.thermostat.common.command.Request;
@@ -78,8 +76,6 @@
 import com.redhat.thermostat.common.command.Response.ResponseType;
 import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.storage.core.AuthToken;
-import com.redhat.thermostat.storage.core.SecureStorage;
 
 public class CommandChannelDelegateTest {
     
@@ -90,7 +86,6 @@
     private static final byte[] ENCODED_RESPONSE_AUTH_FAILED = { 'A', 'U', 'T', 'H' };
     private static final byte[] ENCODED_RESPONSE_ERROR = { 'E', 'R', 'R' };
     
-    private StorageGetter storageGetter;
     private ProcessCreator processCreator;
     private ReceiverRegistry receivers;
     private File binPath;
@@ -112,7 +107,6 @@
         receivers = mock(ReceiverRegistry.class);
         sslConf = mock(SSLConfiguration.class);
         binPath = new File("/path/to/thermostat/home/");
-        storageGetter = mock(StorageGetter.class);
         processCreator = mock(ProcessCreator.class);
         process = mock(Process.class);
         ipcService = mock(AgentIPCService.class);
@@ -148,7 +142,7 @@
         fsUtils = mock(FileSystemUtils.class);
         userInfoBuilder = mock(ProcessUserInfoBuilder.class);
         delegate = new CommandChannelDelegate(receivers, sslConf, binPath, ipcService, 
-                latch, sslConfEncoder, requestDecoder, responseEncoder, storageGetter, userInfoBuilder, 
+                latch, sslConfEncoder, requestDecoder, responseEncoder, userInfoBuilder,
                 fsUtils, processCreator);
         
         startedMessage = mock(IPCMessage.class);
@@ -395,84 +389,6 @@
         assertArrayEquals(ENCODED_RESPONSE_ERROR, result);
     }
     
-    @Test
-    public void testAuthenticateSuccess() throws IOException {
-        SecureStorage secStorage = mock(SecureStorage.class);
-        when(storageGetter.get()).thenReturn(secStorage);
-        
-        RequestReceiver receiver = mock(RequestReceiver.class);
-        Request request = createRequest(receiver);
-        
-        // Create tokens
-        final String authToken = "TXlBdXRoVG9rZW4=";
-        final String clientToken = "TXlDbGllbnRUb2tlbg==";
-        when(request.getParameter(Request.AUTH_TOKEN)).thenReturn(authToken);
-        when(request.getParameter(Request.CLIENT_TOKEN)).thenReturn(clientToken);
-        when(request.getParameter(Request.ACTION)).thenReturn("DoSomething");
-        
-        mockVerifyToken(secStorage, authToken, clientToken);
-        
-        byte[] result = receiveRequestAndReturnResponse(request);
-        verify(receiver).receive(request);
-        assertArrayEquals(ENCODED_RESPONSE_OK, result);
-    }
-    
-    @Test
-    public void testAuthenticateFailed() throws IOException {
-        SecureStorage secStorage = mock(SecureStorage.class);
-        when(storageGetter.get()).thenReturn(secStorage);
-        
-        RequestReceiver receiver = mock(RequestReceiver.class);
-        Request request = createRequest(receiver);
-        
-        // Create tokens
-        final String authToken = "TXlBdXRoVG9rZW4=";
-        final String clientToken = "TXlDbGllbnRUb2tlbg==";
-        when(request.getParameter(Request.AUTH_TOKEN)).thenReturn(authToken);
-        when(request.getParameter(Request.CLIENT_TOKEN)).thenReturn(clientToken);
-        when(request.getParameter(Request.ACTION)).thenReturn("DoSomething");
-        
-        mockVerifyToken(secStorage, "TXlFdmlsVG9rZW4=", clientToken);
-        
-        byte[] result = receiveRequestAndReturnResponse(request);
-        verify(receiver, never()).receive(request);
-        assertArrayEquals(ENCODED_RESPONSE_AUTH_FAILED, result);
-    }
-
-    @Test
-    public void testAuthenticateNPE() throws IOException {
-        SecureStorage secStorage = mock(SecureStorage.class);
-        when(storageGetter.get()).thenReturn(secStorage);
-        
-        RequestReceiver receiver = mock(RequestReceiver.class);
-        Request request = createRequest(receiver);
-        
-        // Create tokens
-        final String authToken = "TXlBdXRoVG9rZW4=";
-        final String clientToken = "TXlDbGllbnRUb2tlbg==";
-        when(request.getParameter(Request.AUTH_TOKEN)).thenReturn(authToken);
-        when(request.getParameter(Request.CLIENT_TOKEN)).thenReturn(clientToken);
-        
-        when(secStorage.verifyToken(any(AuthToken.class), any(String.class))).thenThrow(new NullPointerException());
-        
-        byte[] result = receiveRequestAndReturnResponse(request);
-        verify(receiver, never()).receive(request);
-        assertArrayEquals(ENCODED_RESPONSE_AUTH_FAILED, result);
-    }
-    
-    private void mockVerifyToken(SecureStorage secStorage,
-            final String authToken, final String clientToken) {
-        when(secStorage.verifyToken(any(AuthToken.class), eq("DoSomething"))).thenAnswer(new Answer<Boolean>() {
-            @Override
-            public Boolean answer(InvocationOnMock invocation) throws Throwable {
-                AuthToken token = (AuthToken) invocation.getArguments()[0];
-                boolean authMatches = Arrays.equals(token.getToken(), Base64.decodeBase64(authToken));
-                boolean clientMatches = Arrays.equals(token.getClientToken(), Base64.decodeBase64(clientToken));
-                return authMatches && clientMatches;
-            }
-        });
-    }
-
     private Request createRequest(RequestReceiver receiver) {
         Request request = mock(Request.class);
         when(request.getType()).thenReturn(RequestType.RESPONSE_EXPECTED);
--- a/distribution/pom.xml	Fri May 19 11:37:45 2017 +0200
+++ b/distribution/pom.xml	Fri May 19 11:58:05 2017 +0200
@@ -554,12 +554,12 @@
       <!--<version>${project.version}</version>-->
       <!--<type>zip</type>-->
     <!--</dependency>-->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-cpu-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-    </dependency>
+    <!--<dependency>-->
+      <!--<groupId>com.redhat.thermostat</groupId>-->
+      <!--<artifactId>thermostat-vm-cpu-distribution</artifactId>-->
+      <!--<version>${project.version}</version>-->
+      <!--<type>zip</type>-->
+    <!--</dependency>-->
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-vm-gc-distribution</artifactId>
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri May 19 11:37:45 2017 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri May 19 11:58:05 2017 +0200
@@ -74,7 +74,6 @@
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.Translate;
-import com.redhat.thermostat.storage.core.Storage;
 
 /**
  * This class is thread-safe.
@@ -183,13 +182,6 @@
             // default to success for exit status
             int exitStatus = ExitStatus.EXIT_SUCCESS;
             if (context != null) {
-                ServiceReference storageRef = context.getServiceReference(Storage.class);
-                if (storageRef != null) {
-                    Storage storage = (Storage) context.getService(storageRef);
-                    if (storage != null) {
-                        storage.shutdown();
-                    }
-                }
                 ServiceReference exitStatusRef = context.getServiceReference(ExitStatus.class);
                 if (exitStatusRef != null) {
                     ExitStatus exitStatusService = (ExitStatus) context.getService(exitStatusRef);
--- a/plugins/pom.xml	Fri May 19 11:37:45 2017 +0200
+++ b/plugins/pom.xml	Fri May 19 11:58:05 2017 +0200
@@ -57,7 +57,7 @@
     <!--<module>host-cpu</module>-->
     <!--<module>host-memory</module>-->
     <!--<module>vm-byteman</module>-->
-    <module>vm-cpu</module>
+    <!--<module>vm-cpu</module>-->
     <module>vm-gc</module>
     <!--<module>vm-classstat</module>-->
     <!--<module>vm-compiler</module>-->
--- a/plugins/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java	Fri May 19 11:37:45 2017 +0200
+++ b/plugins/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java	Fri May 19 11:58:05 2017 +0200
@@ -45,7 +45,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
 import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
 import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
 import org.eclipse.jetty.client.HttpClient;
@@ -55,7 +54,7 @@
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
 
-public class VmGcStatDAOImpl extends AbstractDao implements VmGcStatDAO {
+public class VmGcStatDAOImpl implements VmGcStatDAO {
     
     private static final Logger logger = LoggingUtils.getLogger(VmGcStatDAOImpl.class);
     
@@ -94,7 +93,6 @@
         }
     }
 
-    @Override
     public Logger getLogger() {
         return logger;
     }
--- a/plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/Activator.java	Fri May 19 11:37:45 2017 +0200
+++ b/plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/Activator.java	Fri May 19 11:58:05 2017 +0200
@@ -36,16 +36,8 @@
 
 package com.redhat.thermostat.vm.memory.common.internal;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.ServiceTracker;
-
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.VmTlabStatDAO;
 
--- a/plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Fri May 19 11:37:45 2017 +0200
+++ b/plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Fri May 19 11:58:05 2017 +0200
@@ -45,7 +45,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
 import org.eclipse.jetty.client.HttpClient;
@@ -55,7 +54,7 @@
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
 
-class VmMemoryStatDAOImpl extends AbstractDao implements VmMemoryStatDAO {
+class VmMemoryStatDAOImpl implements VmMemoryStatDAO {
 
     private static final Logger logger = LoggingUtils.getLogger(VmMemoryStatDAOImpl.class);
 
@@ -104,7 +103,6 @@
         }
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmTlabStatDAOImpl.java	Fri May 19 11:37:45 2017 +0200
+++ b/plugins/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmTlabStatDAOImpl.java	Fri May 19 11:58:05 2017 +0200
@@ -45,7 +45,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
 import com.redhat.thermostat.vm.memory.common.VmTlabStatDAO;
 import com.redhat.thermostat.vm.memory.common.model.VmTlabStat;
 
@@ -56,7 +55,7 @@
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
 
-class VmTlabStatDAOImpl extends AbstractDao implements VmTlabStatDAO {
+class VmTlabStatDAOImpl implements VmTlabStatDAO {
 
     private static final String GATEWAY_URL = "http://localhost:30000"; // TODO configurable
     private static final String GATEWAY_PATH = "/jvm-memory/0.0.2/";
@@ -106,7 +105,6 @@
         }
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/plugins/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/ActivatorTest.java	Fri May 19 11:37:45 2017 +0200
+++ b/plugins/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/ActivatorTest.java	Fri May 19 11:58:05 2017 +0200
@@ -38,11 +38,8 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
 import org.junit.Test;
 
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012-2017 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.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.model.Pojo;
-
-public abstract class AbstractQuery<T extends Pojo> implements Query<T> {
-
-    public static class Sort {
-        private Key<?> key;
-        private SortDirection direction;
-        public Sort() {
-            this(null, null);
-        }
-
-        public Sort(Key<?> key, SortDirection direction) {
-            this.key = key;
-            this.direction = direction;
-        }
-        public Key<?> getKey() {
-            return key;
-        }
-        public void setKey(Key<?> key) {
-            this.key = key;
-        }
-        public SortDirection getDirection() {
-            return direction;
-        }
-        public void setDirection(SortDirection direction) {
-            this.direction = direction;
-        }
-
-        public int hashCode() {
-            return Objects.hash(key, direction);
-        }
-        public boolean equals(Object obj) {
-            if (obj == null) {
-                return false;
-            }
-            if (obj == this) {
-                return true;
-            }
-            if (!(obj instanceof Sort)) {
-                return false;
-            }
-            Sort other = (Sort) obj;
-            return Objects.equals(key, other.key) && Objects.equals(direction, other.direction);
-        }
-    }
-
-    private List<Sort> sorts;
-    private int limit = -1;
-
-    public AbstractQuery() {
-        sorts = new ArrayList<>();
-    }
-
-    @Override
-    public void sort(Key<?> key, SortDirection direction) {
-        sorts.add(new Sort(key, direction));
-    }
-
-    public List<Sort> getSorts() {
-        return sorts;
-    }
-
-    public void setSorts(List<Sort> sorts) {
-        this.sorts = sorts;
-    }
-
-    @Override
-    public void limit(int limit) {
-        this.limit  = limit;
-    }
-
-    public int getLimit() {
-        return limit;
-    }
-
-    public void setLimit(int limit) {
-        this.limit = limit;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Add.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Write operation to be used for adding new records into
- * storage.
- *
- * @see Remove
- * @see Replace
- * @see Update
- */
-public interface Add<T extends Pojo> extends DataModifyingStatement<T> {
-
-    /**
-     * Sets a field to the specified value. If the same key is
-     * set more than once, the latest value overrides the former value for that
-     * key.
-     * 
-     * @param key
-     *            the name of the field to update.
-     * @param value
-     *            the value with which to update the field.
-     */
-    void set(String key, Object value);
-
-    /**
-     * Applies this {@code Add} operation to storage.
-     *
-     * @throws StorageException if the operation fails
-     */
-    int apply();
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/AggregateQuery.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright 2012-2017 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.Objects;
-
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Common super class for aggregate queries.
- */
-public abstract class AggregateQuery<T extends Pojo> implements Query<T> {
-    
-    public enum AggregateFunction {
-        /**
-         * Aggregate records by counting them.
-         */
-        COUNT,
-        /**
-         * Find distinct values for a {@link Key}
-         */
-        DISTINCT,
-    }
-    
-    protected final Query<T> queryToAggregate;
-    private final AggregateFunction function;
-    // optional Key to aggregate values for
-    private Key<?> aggregateKey;
-    
-    public AggregateQuery(AggregateFunction function, Query<T> queryToAggregate) {
-        this.function = function;
-        this.queryToAggregate = queryToAggregate;
-    }
-    
-    @Override
-    public void where(Expression expr) {
-        queryToAggregate.where(expr);
-    }
-
-    @Override
-    public void sort(Key<?> key,
-            SortDirection direction) {
-        queryToAggregate.sort(key, direction);
-    }
-
-    @Override
-    public void limit(int n) {
-        queryToAggregate.limit(n);
-    }
-
-    @Override
-    public Expression getWhereExpression() {
-        return queryToAggregate.getWhereExpression();
-    }
-    
-    /**
-     * 
-     * @return The function by which to aggregate by.
-     */
-    public AggregateFunction getAggregateFunction() {
-        return this.function;
-    }
-    
-    /**
-     * 
-     * @return An optional {@link Key} to aggregate values for. May be
-     *         {@code null};
-     */
-    public Key<?> getAggregateKey() {
-        return aggregateKey;
-    }
-
-    /**
-     * Sets an optional {@link Key} to aggregate values for.
-     * @param aggregateKey Must not be {@code null}.
-     * @throws NullPointerException If the aggregate key was {@code null}
-     */
-    public void setAggregateKey(Key<?> aggregateKey) {
-        this.aggregateKey = Objects.requireNonNull(aggregateKey);
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/BackingStorage.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012-2017 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.core.AggregateQuery.AggregateFunction;
-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);
-    
-    <T extends Pojo> AggregateQuery<T> createAggregateQuery(AggregateFunction function, Category<T> category);
-    
-    <T extends Pojo> Add<T> createAdd(Category<T> category);
-    
-    <T extends Pojo> Replace<T> createReplace(Category<T> category);
-    
-    <T extends Pojo> Update<T> createUpdate(Category<T> category);
-    
-    <T extends Pojo> Remove<T> createRemove(Category<T> category);
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Marker interface for {@link Statement}s which perform write operations on
- * storage. These statements usually only return success/failure responses or
- * more specific error codes.
- *
- */
-public interface DataModifyingStatement<T extends Pojo> extends Statement<T> {
-
-    /**
-     * Default success status. The status code itself has no meaning other than
-     * indicating success. Suitable to be returned on {@link #apply()}.
-     */
-    public static final int DEFAULT_STATUS_SUCCESS = 0;
-    /**
-     * Default failure status. The status code itself has no meaning other than
-     * indicating failure. Suitable to be returned on {@link #apply()}.
-     */
-    public static final int DEFAULT_STATUS_FAILURE = -1;
-    
-    /**
-     * Executes this statement.
-     *
-     * @throws StorageException if this statement fails to apply
-     * 
-     * @return a number greater than or equal to zero on success. A negative
-     *         failure code otherwise.
-     */
-    int apply();
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/DbService.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright 2012-2017 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.annotations.Service;
-import com.redhat.thermostat.storage.core.ConnectionException;
-import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
-
-/**
- * DbService provides API for handling database (i.e. {@link Storage})
- * connections. Once {@link DbService#connect()} has been called, the current
- * instance can be retrieved as service. This registered service instance could
- * then be used to disconnect from storage.
- * 
- * @see {@link DbServiceFactory}
- */
-@Service
-public interface DbService {
-
-    /**
-     * Connects to {@link Storage} and registers {@link Storage} instance which
-     * was used for the connection as a service.
-     * 
-     * <br/>
-     * <br/>
-     * <strong>Pre:</strong> Neither DbService nor Storage are registered as
-     * services. <br/>
-     * <strong>Post:</strong> Both DbService and Storage are registered as
-     * services.
-     * 
-     * @throws ConnectionException
-     *             If DB connection cannot be established.
-     */
-    void connect() throws ConnectionException;
-
-    /**
-     * Disconnects from {@link Storage}.
-     * 
-     * <br/>
-     * <br/>
-     * <strong>Pre:</strong> Both DbService and Storage are registered as
-     * services.
-     * <br/>
-     * <strong>Post:</strong> Neither DbService nor Storage are registered as
-     * services.
-     * 
-     * @throws ConnectionException
-     */
-    void disconnect() throws ConnectionException;
-
-    /**
-     * @returns the storage URL which was used for connection.
-     * 
-     * @throws IllegalStateException
-     *             if not connected to storage.
-     */
-    String getConnectionUrl();
-
-    /**
-     * @returns the username which was used for the connection
-     * @see Connection#getUsername()
-     */
-    String getUserName();
-
-    /**
-     * Registers the supplied ConnectionListener to be notified when the status
-     * of the database connection changes.
-     * 
-     * @param listener
-     *            - the listener to be registered
-     */
-    void addConnectionListener(ConnectionListener listener);
-
-    /**
-     * Unregisters the supplied ConnectionListener if it was previously
-     * registered via {@link #addConnectionListener(ConnectionListener)}.
-     * 
-     * @param listener
-     *            - the listener to be unregistered
-     */
-    void removeConnectionListener(ConnectionListener listener);
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/DbServiceFactory.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright 2012-2017 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.shared.config.SSLConfiguration;
-import com.redhat.thermostat.storage.internal.DbServiceImpl;
-
-/*
- * Factory in order to be able to hide the DbService implementation. Note that
- * this package will be part of Export-Package whereas the package where *Impl
- * classes are won't be.
- *
- */
-/**
- * Factory for creating new {@link DbService} instances.
- * 
- * @see {@link DbService}, {@link StorageProvider}.
- *
- */
-public class DbServiceFactory {
-
-    /**
-     * Creates a <strong>new</strong> {@link DbService} instance which can be
-     * used to establish a connection with {@link Storage}. Note that the actual
-     * {@link StorageProvider} which will be used for the connection is looked
-     * up based on registered StorageProvider OSGi services and URLs they are
-     * able to handle. If a {@link DbService} instance is already registered as
-     * a service, users are encouraged to use that instance for disconnecting
-     * from storage.
-     * 
-     * @param dbUrl
-     *            The URL to the storage endpoint. For example
-     *            {@code mongodb://127.0.0.1:27518} or
-     *            {@code https://storage.example.com/storage}.
-     * @param creds
-     *            The credentials to use for the connection.
-     * @param sslConf
-     *            The TLS configuration to use for the connection.
-     * @return A new {@link DbService} instance which can be used for
-     *         establishing new storage connections.
-     * @throws StorageException
-     *             If no matching {@link StorageProvider} could be found for the
-     *             given dbUrl.
-     */
-    public DbService createDbService(String dbUrl, StorageCredentials creds, SSLConfiguration sslConf) throws StorageException {
-        return DbServiceImpl.create(dbUrl, creds, sslConf);
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostBoundaryPojoGetter.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostBoundaryPojoGetter.java	Fri May 19 11:58:05 2017 +0200
@@ -39,11 +39,9 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
 
-public class HostBoundaryPojoGetter<T extends TimeStampedPojo> extends AbstractDao {
+public class HostBoundaryPojoGetter<T extends TimeStampedPojo>  {
 
     // QUERY %s WHERE 'agentId' = ?s AND \
     //                        SORT 'timeStamp' DSC  \
@@ -63,13 +61,11 @@
 
     private static final Logger logger = LoggingUtils.getLogger(HostBoundaryPojoGetter.class);
 
-    private final Storage storage;
     private final Category<T> cat;
     private final String queryNewest;
     private final String queryOldest;
 
-    public HostBoundaryPojoGetter(Storage storage, Category<T> cat) {
-        this.storage = storage;
+    public HostBoundaryPojoGetter(Category<T> cat) {
         this.cat = cat;
         this.queryNewest = String.format(DESC_NEWEST_HOST_STAT, cat.getName());
         this.queryOldest = String.format(DESC_OLDEST_HOST_STAT, cat.getName());
@@ -100,13 +96,7 @@
     }
 
     private T runAgentIdQuery(final String agentId, final String descriptor) {
-        return executeQuery(new AbstractDaoQuery<T>(storage, cat, descriptor) {
-            @Override
-            public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-                preparedStatement.setString(0, agentId);
-                return preparedStatement;
-            }
-        }).head();
+        return null;
     }
 
     //Package private for testing
@@ -118,7 +108,6 @@
         return queryOldest;
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java	Fri May 19 11:58:05 2017 +0200
@@ -40,14 +40,12 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
 
 /**
  * @see HostTimeIntervalPojoListGetter
  */
-public class HostLatestPojoListGetter<T extends TimeStampedPojo> extends AbstractDao {
+public class HostLatestPojoListGetter<T extends TimeStampedPojo>  {
 
     public static final String HOST_LATEST_QUERY_FORMAT = "QUERY %s WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s AND '"
@@ -56,12 +54,10 @@
 
     private static final Logger logger = LoggingUtils.getLogger(HostLatestPojoListGetter.class);
 
-    private final Storage storage;
     private final Category<T> cat;
     private final String queryLatest;
 
-    public HostLatestPojoListGetter(Storage storage, Category<T> cat) {
-        this.storage = storage;
+    public HostLatestPojoListGetter(Category<T> cat) {
         this.cat = cat;
         this.queryLatest = String.format(HOST_LATEST_QUERY_FORMAT, cat.getName());
     }
@@ -75,14 +71,7 @@
     }
 
     public List<T> getLatest(final AgentId agentId, final long since) {
-        return executeQuery(new AbstractDaoQuery<T>(storage, cat, queryLatest) {
-            @Override
-            public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-                preparedStatement.setString(0, agentId.get());
-                preparedStatement.setLong(1, since);
-                return preparedStatement;
-            }
-        }).asList();
+        return null;
     }
 
     // package private for testing
@@ -90,7 +79,6 @@
         return queryLatest;
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostTimeIntervalPojoListGetter.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostTimeIntervalPojoListGetter.java	Fri May 19 11:58:05 2017 +0200
@@ -40,14 +40,12 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
 
 /**
  * @see HostLatestPojoListGetter
  */
-public class HostTimeIntervalPojoListGetter<T extends TimeStampedPojo> extends AbstractDao {
+public class HostTimeIntervalPojoListGetter<T extends TimeStampedPojo>  {
 
     public static final String HOST_INTERVAL_QUERY_FORMAT = "QUERY %s WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s AND '"
@@ -57,12 +55,10 @@
 
     private static final Logger logger = LoggingUtils.getLogger(HostTimeIntervalPojoListGetter.class);
 
-    private final Storage storage;
     private final Category<T> cat;
     private final String query;
 
-    public HostTimeIntervalPojoListGetter(Storage storage, Category<T> cat) {
-        this.storage = storage;
+    public HostTimeIntervalPojoListGetter(Category<T> cat) {
         this.cat = cat;
         this.query = String.format(HOST_INTERVAL_QUERY_FORMAT, cat.getName());
     }
@@ -76,15 +72,7 @@
     }
 
     public List<T> getLatest(final AgentId agentId, final long since, final long to) {
-        return executeQuery(new AbstractDaoQuery<T>(storage, cat, query) {
-            @Override
-            public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-                preparedStatement.setString(0, agentId.get());
-                preparedStatement.setLong(1, since);
-                preparedStatement.setLong(2, to);
-                return preparedStatement;
-            }
-        }).asList();
+        return null;
     }
 
     // package private for testing
@@ -92,7 +80,6 @@
         return query;
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/ParsedStatement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * An intermediary representation of a {@link PreparedStatement}.
- * 
- */
-public interface ParsedStatement<T extends Pojo> {
-
-    /**
-     * Patches a statement, setting free variables. After patching, the
-     * statement is ready for execution.
-     * 
-     * @param params
-     *            The ordered list of values/types of free parameters.
-     * @return The statement ready for execution.
-     * @throws IllegalPatchException
-     *             If the patching fails for some reason.
-     */
-    Statement<T> patchStatement(PreparedParameter[] params)
-            throws IllegalPatchException;
-
-    /**
-     * 
-     * @return The number of free variables which the original prepared
-     *         statement string descriptor contained.
-     */
-    int getNumParams();
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameter.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Represents a prepared parameter.
- *
- * @see PreparedParameters
- */
-public class PreparedParameter {
-
-    private Object value;
-    // The type of the value field. This is the instantiable component type for
-    // Pojo array values.
-    private Class<?> type;
-    
-    PreparedParameter(Object value, Class<?> type) {
-        this.value = value;
-        this.type = type;
-    }
-    
-    public PreparedParameter() {
-        // nothing. Exists for serialization purposes.
-    }
-
-    public Object getValue() {
-        return value;
-    }
-
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    public Class<?> getType() {
-        return type;
-    }
-
-    public void setType(Class<?> type) {
-        this.type = type;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright 2012-2017 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.lang.reflect.Modifier;
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.model.Pojo;
-
-/**
- * 
- * Shared class for setting prepared parameters.
- *
- */
-public final class PreparedParameters implements PreparedStatementSetter {
-
-    private PreparedParameter[] params;
-    
-    public PreparedParameters(int numParams) {
-        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);
-    }
-
-    @Override
-    public void setLongList(int paramIndex, long[] paramValue) {
-        setType(paramIndex, paramValue, long[].class);
-    }
-
-    @Override
-    public void setInt(int paramIndex, int paramValue) {
-        setType(paramIndex, paramValue, int.class);
-    }
-
-    @Override
-    public void setIntList(int paramIndex, int[] paramValue) {
-        setType(paramIndex, paramValue, int[].class);
-    }
-
-    @Override
-    public void setBoolean(int paramIndex, boolean paramValue) {
-        setType(paramIndex, paramValue, boolean.class);
-    }
-
-    @Override
-    public void setBooleanList(int paramIndex, boolean[] paramValue) {
-        setType(paramIndex, paramValue, boolean[].class);
-    }
-
-    @Override
-    public void setString(int paramIndex, String paramValue) {
-        setType(paramIndex, paramValue, String.class);
-    }
-
-    @Override
-    public void setStringList(int paramIndex, String[] paramValue) {
-        setType(paramIndex, paramValue, String[].class);
-    }
-
-    @Override
-    public void setDouble(int paramIndex, double paramValue) {
-        setType(paramIndex, paramValue, double.class);
-    }
-
-    @Override
-    public void setDoubleList(int paramIndex, double[] paramValue) {
-        setType(paramIndex, paramValue, double[].class);
-    }
-
-    @Override
-    public void setPojo(int paramIndex, Pojo paramValue) {
-        // null Pojo value would make array and non-array types
-        // indistinguishable for serialization
-        Objects.requireNonNull(paramValue);
-        Class<?> runtimeType = paramValue.getClass();
-        performPojoChecks(runtimeType, "Type");
-        setType(paramIndex, paramValue, runtimeType);
-    }
-
-    @Override
-    public void setPojoList(int paramIndex, Pojo[] paramValue) {
-        // null Pojo value would make array and non-array types
-        // indistinguishable for serialization
-        Objects.requireNonNull(paramValue);
-        Class<?> componentType = paramValue.getClass().getComponentType();
-        performPojoChecks(componentType, "Component type");
-        setType(paramIndex, paramValue, componentType);
-    }
-    
-    private void performPojoChecks(Class<?> type, String errorMsgPrefix) {
-        if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
-            // Due to serealization we only allow concrete instantiable types.
-            // Instantiation would fail later in ThermostatGSONConverter for this
-            // reason anyway. Let's do this check early.            
-            throw new IllegalArgumentException(errorMsgPrefix + "'" +
-                        type.getName() + "' not instantiable!");
-        }
-    }
-
-    private void setType(int paramIndex, Object paramValue, Class<?> paramType) {
-        if (paramIndex >= params.length) {
-            throw new IllegalArgumentException("Parameter index '" + paramIndex + "' out of range.");
-        }
-        PreparedParameter param = new PreparedParameter(paramValue, paramType);
-        params[paramIndex] = param;
-    }
-    
-    public PreparedParameter[] getParams() {
-        return params;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-
-/**
- * A prepared statement.
- * 
- * @see Statement
- * @see DataModifyingStatement
- * @see Storage#prepareStatement(StatementDescriptor)
- *
- */
-public interface PreparedStatement<T extends Pojo> extends PreparedStatementSetter {
-    
-    void setBoolean(int paramIndex, boolean paramValue);
-    
-    void setLong(int paramIndex, long paramValue);
-    
-    void setInt(int paramIndex, int paramValue);
-    
-    void setString(int paramIndex, String paramValue);
-    
-    void setStringList(int paramIndex, String[] paramValue);
-
-    /**
-     * Executes a predefined {@link DataModifyingStatement}.
-     * 
-     * @return a non-zero error code on failure. Zero otherwise.
-     * 
-     * @throws StatementExecutionException
-     *             If the prepared statement wasn't valid for execution.
-     * @throws StorageException
-     *             If the underlying storage throws an exception while executing
-     *             this statement
-     */
-    int execute() throws StatementExecutionException;
-
-    /**
-     * Executes a predefined {@link Query}.
-     * 
-     * @return a {@link Cursor} as a result to the underlying {@link Query}
-     * 
-     * @throws StatementExecutionException
-     *             If the prepared statement wasn't valid for execution.
-     * @throws StorageException
-     *             If the underlying storage throws an exception while executing
-     *             this query
-     */
-    Cursor<T> executeQuery() throws StatementExecutionException;
-    
-    /**
-     * @return An intermediary representation of this prepared statement.
-     */
-    ParsedStatement<T> getParsedStatement();
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementFactory.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement.PreparedStatementImpl;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/**
- * Factory for instantiating a {@link PreparedStatement}.
- *
- */
-public class PreparedStatementFactory {
-
-    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
-        // factory.
-        return new PreparedStatementImpl<>(storage, desc);
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementSetter.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Package private interface in order to ensure consistency of
- * setters between {@link PreparedStatement} and {@link PreparedParamenters}.
- *
- */
-interface PreparedStatementSetter {
-
-    void setBoolean(int paramIndex, boolean paramValue);
-    
-    void setBooleanList(int paramIndex, boolean[] paramValue);
-    
-    void setLong(int paramIndex, long paramValue);
-    
-    void setLongList(int paramIndex, long[] paramValue);
-    
-    void setInt(int paramIndex, int paramValue);
-    
-    void setIntList(int paramIndex, int[] paramValue);
-    
-    void setString(int paramIndex, String paramValue);
-    
-    void setStringList(int paramIndex, String[] paramValue);
-    
-    void setDouble(int paramIndex, double paramValue);
-    
-    void setDoubleList(int paramIndex, double[] paramValue);
-    
-    void setPojo(int paramIndex, Pojo paramValue);
-    
-    void setPojoList(int paramIndex, Pojo[] paramValue);
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Describes what data should be fetched.
- */
-public interface Query<T extends Pojo> extends Statement<T> {
-
-    enum SortDirection {
-        ASCENDING(1),
-        DESCENDING(-1);
-
-        private int value;
-
-        private SortDirection(int value) {
-            this.value = value;
-        }
-
-        public int getValue() {
-            return value;
-        }
-    }
-
-    void where(Expression expr);
-    
-    void sort(Key<?> key, SortDirection direction);
-
-    void limit(int n);
-
-    /**
-     * @throws StorageException
-     *             If the operation fails
-     *
-     * @return a {@link Cursor} that can be used to iterate over the results.
-     */
-    Cursor<T> execute();
-    
-    Expression getWhereExpression();
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,609 +0,0 @@
-/*
- * Copyright 2012-2017 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.io.InputStream;
-import java.util.Objects;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.Constants;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.perflog.PerformanceLogFormatter;
-import com.redhat.thermostat.shared.perflog.PerformanceLogFormatter.LogTag;
-import com.redhat.thermostat.storage.internal.CountingDecorator;
-import com.redhat.thermostat.storage.internal.ThreadPoolSizeRetriever;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-
-public class QueuedStorage implements Storage {
-    
-    private static final Logger logger = LoggingUtils.getLogger(QueuedStorage.class);
-    private static final int SHUTDOWN_TIMEOUT_SECONDS = 3;
-
-    /*
-     * True if and only if the delegate is a backing storage (such as mongodb)
-     * and it is used as a backing storage for proxied storage (such as web).
-     */
-    protected final boolean isBackingStorageInProxy;
-    /*
-     * True if and only if statements should get timed and logged.
-     */
-    protected final boolean isTimedStatements;
-    // performance logger. may be null
-    protected final PerformanceLogFormatter perfLogFormatter;
-    protected final Storage delegate;
-    protected final ExecutorService executor;
-    protected final ExecutorService fileExecutor;
-    
-    private abstract static class SettingDecorator<T extends Pojo> implements PreparedStatementSetter, PreparedStatement<T> {
-        
-        protected final PreparedStatement<T> stmtDelegate;
-        
-        private SettingDecorator(PreparedStatement<T> decoratee) {
-            this.stmtDelegate = decoratee;
-        }
-        
-        @Override
-        public void setBooleanList(int paramIndex, boolean[] paramValue) {
-            stmtDelegate.setBooleanList(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setLongList(int paramIndex, long[] paramValue) {
-            stmtDelegate.setLongList(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setIntList(int paramIndex, int[] paramValue) {
-            stmtDelegate.setIntList(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setDouble(int paramIndex, double paramValue) {
-            stmtDelegate.setDouble(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setDoubleList(int paramIndex, double[] paramValue) {
-            stmtDelegate.setDoubleList(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setPojo(int paramIndex, Pojo paramValue) {
-            stmtDelegate.setPojo(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setPojoList(int paramIndex, Pojo[] paramValue) {
-            stmtDelegate.setPojoList(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setBoolean(int paramIndex, boolean paramValue) {
-            stmtDelegate.setBoolean(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setLong(int paramIndex, long paramValue) {
-            stmtDelegate.setLong(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setInt(int paramIndex, int paramValue) {
-            stmtDelegate.setInt(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setString(int paramIndex, String paramValue) {
-            stmtDelegate.setString(paramIndex, paramValue);
-        }
-
-        @Override
-        public void setStringList(int paramIndex, String[] paramValue) {
-            stmtDelegate.setStringList(paramIndex, paramValue);
-        }
-        
-    }
-    
-    class QueuedStatementDecorator<T extends Pojo> implements Statement<T> {
-        
-        private final Statement<T> stmt;
-        
-        private QueuedStatementDecorator(Statement<T> delegate) {
-            this.stmt = delegate;
-        }
-
-        @Override
-        public Statement<T> getRawDuplicate() {
-            return stmt.getRawDuplicate();
-        }
-    }
-    
-    abstract class QueuedQueryDecorator<T extends Pojo> extends QueuedStatementDecorator<T> implements Query<T> {
-
-        protected final Query<T> query;
-        private QueuedQueryDecorator(Query<T> delegate) {
-            super(delegate);
-            this.query = delegate;
-        }
-        
-        @Override
-        public void where(Expression expr) {
-            query.where(expr);
-        }
-
-        @Override
-        public void sort(Key<?> key,
-                com.redhat.thermostat.storage.core.Query.SortDirection direction) {
-            query.sort(key, direction);
-        }
-
-        @Override
-        public void limit(int n) {
-            query.limit(n);
-        }
-
-        public abstract Cursor<T> execute();
-
-        @Override
-        public Expression getWhereExpression() {
-            return query.getWhereExpression();
-        }
-        
-    }
-    
-    class QueuedWrite<T extends Pojo> extends QueuedStatementDecorator<T> implements DataModifyingStatement<T> {
-
-        protected final DataModifyingStatement<T> write;
-        
-        private QueuedWrite(DataModifyingStatement<T> delegate) {
-            super(delegate);
-            this.write = delegate;
-        }
-        
-        @Override
-        public int apply() {
-            executor.execute(new Runnable() {
-                
-                @Override
-                public void run() {
-                    doApply();
-                }
-            });
-            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
-        }
-        
-        // Allows for timed decoration
-        protected int doApply() {
-            return write.apply();
-        }
-        
-    }
-    
-    abstract class QueuedParsedStatementDecorator<T extends Pojo> implements ParsedStatement<T> {
-
-        protected final ParsedStatement<T> parsedDelegate;
-        
-        private QueuedParsedStatementDecorator(ParsedStatement<T> delegate) {
-            this.parsedDelegate = delegate;
-        }
-        
-        @Override
-        public abstract Statement<T> patchStatement(PreparedParameter[] params) throws IllegalPatchException;
-
-        @Override
-        public int getNumParams() {
-            return parsedDelegate.getNumParams();
-        }
-        
-    }
-    
-    class QueuedParsedStatement<T extends Pojo> extends QueuedParsedStatementDecorator<T> {
-        
-        private QueuedParsedStatement(ParsedStatement<T> delegate) {
-            super(delegate);
-        }
-
-        @Override
-        public Statement<T> patchStatement(PreparedParameter[] params)
-                throws IllegalPatchException {
-            Statement<T> stmt = parsedDelegate.patchStatement(params);
-            if (stmt instanceof DataModifyingStatement) {
-                DataModifyingStatement<T> target = (DataModifyingStatement<T>)stmt;
-                return new QueuedWrite<>(target);
-            } else if (stmt instanceof Query) {
-                // Queries are not queued
-                return stmt;
-            } else {
-                // We only have two statement types: reads and writes.
-                throw new IllegalStateException("Should not reach here"); 
-            }
-        }
-        
-    }
-    
-    static class TimedStatement {
-        private static final String DB_READ_PREFIX = "DB_READ";
-        private static final String DB_WRITE_PREFIX = "DB_WRITE";
-        private static final String DB_WRITE_FORMAT = DB_WRITE_PREFIX + "(%s) %s";
-        private static final String DB_READ_FORMAT = DB_READ_PREFIX + " %s";
-    }
-    
-    class TimedQuery<T extends Pojo> extends QueuedQueryDecorator<T> {
-
-        private final Query<T> queryDelegate;
-        private final PerformanceLogFormatter perfLogFormatter;
-        private final String descriptor;
-        
-        private TimedQuery(Query<T> delegate, PerformanceLogFormatter perfLogFormatter, String descriptor) {
-            super(delegate);
-            this.queryDelegate = delegate;
-            this.perfLogFormatter = perfLogFormatter;
-            this.descriptor = descriptor;
-        }
-
-        @Override
-        public Cursor<T> execute() {
-            long start = System.nanoTime();
-            Cursor<T> result = queryDelegate.execute();
-            long end = System.nanoTime();
-            String msg = String.format(TimedStatement.DB_READ_FORMAT, descriptor);
-            logger.log(LoggingUtils.LogLevel.PERFLOG.getLevel(), perfLogFormatter.format(LogTag.STORAGE_BACKING_PROXIED, msg, (end - start)));
-            return result;
-        }
-        
-    }
-    
-    class TimedWrite<T extends Pojo> extends QueuedWrite<T> implements DataModifyingStatement<T> {
-
-        private final QueuedWrite<T> write;
-        private final PerformanceLogFormatter perfLogFormatter;
-        private final String descriptor;
-        
-        private TimedWrite(QueuedWrite<T> delegate, PerformanceLogFormatter perfLogFormatter, String descriptor) {
-            super(delegate);
-            this.write = delegate;
-            this.perfLogFormatter = perfLogFormatter;
-            this.descriptor = descriptor;
-        }
-
-        @Override
-        public int apply() {
-            executor.execute(new Runnable() {
-                
-                @Override
-                public void run() {
-                    long start = System.nanoTime();
-                    int retval = write.doApply();
-                    long end = System.nanoTime();
-                    String msg = String.format(TimedStatement.DB_WRITE_FORMAT, retval, descriptor);
-                    logger.log(LoggingUtils.LogLevel.PERFLOG.getLevel(), perfLogFormatter.format(LogTag.STORAGE_BACKING_PROXIED, msg, (end - start)));
-                }
-                
-            });
-            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
-        }
-        
-    }
-    
-    class TimedParsedStatement<T extends Pojo> extends QueuedParsedStatementDecorator<T> {
-
-        private final PerformanceLogFormatter perfLogFormatter;
-        private final String descriptor;
-        
-        private TimedParsedStatement(ParsedStatement<T> delegate, PerformanceLogFormatter perfLogFormatter, String descriptor) {
-            super(delegate);
-            this.perfLogFormatter = perfLogFormatter;
-            this.descriptor = descriptor;
-        }
-        
-        @Override
-        public Statement<T> patchStatement(PreparedParameter[] params)
-                throws IllegalPatchException {
-            Statement<T> stmt = parsedDelegate.patchStatement(params);
-            if (stmt instanceof DataModifyingStatement) {
-                QueuedWrite<T> target = (QueuedWrite<T>)stmt;
-                return new TimedWrite<>(target, perfLogFormatter, descriptor);
-            } else if (stmt instanceof Query) {
-                Query<T> target = (Query<T>)stmt;
-                return new TimedQuery<>(target, perfLogFormatter, descriptor);
-            } else {
-                // We only have two statement types: reads and writes.
-                throw new IllegalStateException("Should not reach here");
-            }
-        }
-        
-    }
-    
-    /*
-     * Decorates statement executions so that they get timed and results logged
-     * via the provided PerformanceLogger.
-     */
-    class TimedPreparedStatement<T extends Pojo> extends SettingDecorator<T> implements PreparedStatement<T> {
-        
-        private static final String DB_READ_PREFIX = "DB_READ";
-        private static final String DB_WRITE_PREFIX = "DB_WRITE";
-        private static final String DB_WRITE_FORMAT = DB_WRITE_PREFIX + "(%s) %s";
-        private static final String DB_READ_FORMAT = DB_READ_PREFIX + " %s";
-        private final PerformanceLogFormatter perfLogFormatter;
-        private final String descriptor;
-        
-        private TimedPreparedStatement(QueuedPreparedStatement<T> decoratee, PerformanceLogFormatter perfLogFormatter, String descriptor) {
-            super(decoratee);
-            this.perfLogFormatter = perfLogFormatter;
-            this.descriptor = descriptor;
-        }
-
-        @Override
-        public Cursor<T> executeQuery() throws StatementExecutionException {
-            long start = System.nanoTime();
-            Cursor<T> result = stmtDelegate.executeQuery();
-            long end = System.nanoTime();
-            String msg = String.format(DB_READ_FORMAT, descriptor);
-            logger.log(LoggingUtils.LogLevel.PERFLOG.getLevel(), perfLogFormatter.format(LogTag.STORAGE_FRONT_END, msg, (end - start)));
-            return result;
-        }
-        
-        @Override
-        public int execute() throws StatementExecutionException {
-            executor.execute(new Runnable() {
-                
-                @Override
-                public void run() {
-                    try {
-                        long start = System.nanoTime();
-                        QueuedPreparedStatement<T> d = (QueuedPreparedStatement<T>)stmtDelegate;
-                        int retval = d.doExecute();
-                        long end = System.nanoTime();
-                        String msg = String.format(DB_WRITE_FORMAT, retval, descriptor);
-                        logger.log(LoggingUtils.LogLevel.PERFLOG.getLevel(), perfLogFormatter.format(LogTag.STORAGE_FRONT_END, msg, (end - start)));
-                    } catch (StatementExecutionException e) {
-                        // There isn't much we can do in case of invalid
-                        // patch or the likes. Log it and move on.
-                        logger.log(Level.WARNING, "Failed to execute statement", e);
-                    }
-                }
-            });
-            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
-        }
-
-        /*
-         * For proxied prepared statements we never actually call the underlying
-         * execute() and executeQuery() methods for performance reasons. We
-         * simply use previously prepared statements and use the parsed result
-         * of them. Thus, in order to make backing storages queued too, we
-         * need to decorate them this way.
-         */
-        @Override
-        public ParsedStatement<T> getParsedStatement() {
-            if (isBackingStorageInProxy) {
-                ParsedStatement<T> target = stmtDelegate.getParsedStatement();
-                return new TimedParsedStatement<>(target, perfLogFormatter, descriptor);
-            } else {
-                return stmtDelegate.getParsedStatement();
-            }
-        }
-        
-    }
-
-    /*
-     * Decorates PreparedStatement.execute() so that executions of writes
-     * are queued.
-     */
-    class QueuedPreparedStatement<T extends Pojo> extends SettingDecorator<T> implements PreparedStatement<T> {
-        
-        private QueuedPreparedStatement(PreparedStatement<T> delegate) {
-            super(Objects.requireNonNull(delegate));
-        }
-
-        @Override
-        public int execute() throws StatementExecutionException {
-            if (isBackingStorageInProxy) {
-                String msg = "Did not expect to get called for backing storage in proxied setup.";
-                throw new AssertionError(msg);
-            }
-            executor.execute(new Runnable() {
-                
-                @Override
-                public void run() {
-                    try {
-                        doExecute();
-                    } catch (StatementExecutionException e) {
-                        // There isn't much we can do in case of invalid
-                        // patch or the likes. Log it and move on.
-                        logger.log(Level.WARNING, "Failed to execute statement", e);
-                    }
-                }
-            });
-            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
-        }
-
-        @Override
-        public Cursor<T> executeQuery() throws StatementExecutionException {
-            if (isBackingStorageInProxy) {
-                String msg = "Did not expect to get called for backing storage in proxied setup.";
-                throw new AssertionError(msg);
-            }
-            return stmtDelegate.executeQuery();
-        }
-        
-        /*
-         * For proxied prepared statements we never actually call the underlying
-         * execute() and executeQuery() methods for performance reasons. We
-         * simply use previously prepared statements and use the parsed result
-         * of them. Thus, in order to make backing storages queued too, we
-         * need to decorate them this way.
-         */
-        @Override
-        public ParsedStatement<T> getParsedStatement() {
-            if (isBackingStorageInProxy) {
-                ParsedStatement<T> target = stmtDelegate.getParsedStatement();
-                return new QueuedParsedStatement<>(target);
-            } else {
-                return stmtDelegate.getParsedStatement();
-            }
-        }
-        
-        // This is to allow for proper decoration of it if timing is turned on.
-        private int doExecute() throws StatementExecutionException {
-            return stmtDelegate.execute();
-        }
-        
-    }
-    
-    public QueuedStorage(Storage delegate) {
-        this(delegate, null);
-    }
-    
-    public QueuedStorage(Storage delegate, PerformanceLogFormatter perfLogFormatter) {
-        this(delegate, perfLogFormatter, new ThreadPoolSizeRetriever().getPoolSize());
-    }
-    
-    QueuedStorage(Storage delegate, PerformanceLogFormatter perflogFormatter, int poolSize) {
-        this(delegate, Executors.newFixedThreadPool(poolSize), Executors.newFixedThreadPool(poolSize), perflogFormatter);
-    }
-
-    QueuedStorage(Storage delegate, ExecutorService executor, ExecutorService fileExecutor) {
-        this(delegate, executor, fileExecutor, null);
-    }
-    
-    QueuedStorage(Storage delegate, ExecutorService executor, ExecutorService fileExecutor, PerformanceLogFormatter perfLogFormatter) {
-        this.delegate = delegate;
-        this.fileExecutor = fileExecutor;
-        this.isBackingStorageInProxy = !(delegate instanceof SecureStorage) && Boolean.getBoolean(Constants.IS_PROXIED_STORAGE);
-        this.isTimedStatements = LoggingUtils.getEffectiveLogLevel(logger).intValue() <= LoggingUtils.LogLevel.PERFLOG.getLevel().intValue();
-        // set up queue counting executor if so requested
-        if (isTimedStatements) {
-            LogTag logTag = (isBackingStorageInProxy ? LogTag.STORAGE_BACKING_PROXIED : LogTag.STORAGE_FRONT_END);
-            this.executor = new CountingDecorator(executor, perfLogFormatter, logTag);
-        } else {
-            this.executor = executor;
-        }
-        this.perfLogFormatter = perfLogFormatter;
-    }
-
-    ExecutorService getExecutor() {
-        return executor;
-    }
-
-    ExecutorService getFileExecutor() {
-        return fileExecutor;
-    }
-
-    @Override
-    public void purge(final String agentId) {
-
-        executor.execute(new Runnable() {
-            
-            @Override
-            public void run() {
-                delegate.purge(agentId);
-            }
-
-        });
-
-    }
-
-    @Override
-    public void saveFile(final String filename, final InputStream data, final SaveFileListener listener) {
-        fileExecutor.execute(new Runnable() {
-            @Override
-            public void run() {
-                delegate.saveFile(filename, data, listener);
-            }
-        });
-    }
-
-    @Override
-    public InputStream loadFile(String filename) {
-        return delegate.loadFile(filename);
-    }
-
-    @Override
-    public void registerCategory(final Category<?> category) {
-        delegate.registerCategory(category);
-    }
-    
-    @Override
-    public <T extends Pojo> PreparedStatement<T> prepareStatement(final StatementDescriptor<T> desc)
-            throws DescriptorParsingException {
-        PreparedStatement<T> decoratee = delegate.prepareStatement(desc);
-        QueuedPreparedStatement<T> queuedPreparedStatement = new QueuedPreparedStatement<>(decoratee);
-        return decorateWithTimingLoggerIfNecessary(queuedPreparedStatement, desc);
-    }
-    
-    private <T extends Pojo> PreparedStatement<T> decorateWithTimingLoggerIfNecessary(QueuedPreparedStatement<T> decoratee, StatementDescriptor<T> desc) {
-        if (isTimedStatements) {
-            return new TimedPreparedStatement<>(decoratee, this.perfLogFormatter, desc.getDescriptor());
-        }
-        return decoratee;
-    }
-    
-    @Override
-    public Connection getConnection() {
-        return delegate.getConnection();
-    }
-
-    @Override
-    public void shutdown() {
-        /*
-         * First shut down executors. This may trigger some pushes to the
-         * storage implementation (a.k.a. delegate). Hence, this should get
-         * shut down last as this closes the connection etc.
-         */
-        try {
-            executor.shutdown();
-            executor.awaitTermination(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-        } catch (InterruptedException ex) {
-            // Fall through. 
-        }
-        try {
-            fileExecutor.shutdown();
-            fileExecutor.awaitTermination(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-        } catch (InterruptedException ex) {
-            // Fall through. 
-        }
-        delegate.shutdown();
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Remove.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Write operation to be used for removing records from storage.
- * 
- * @see Add
- * @see Update
- * @see Replace
- */
-public interface Remove<T extends Pojo> extends DataModifyingStatement<T> {
-
-    /**
-     * Boolean expression in order to restrict the set of records to be removed
-     * from storage.
-     * 
-     * @param where
-     *            The boolean expression.
-     */
-    void where(Expression where);
-    
-    /**
-     * Applies this remove operation.
-     *
-     * @throws StorageException if this operation fails
-     */
-    int apply();
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Replace.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Write operation which should be used if any existing record should get
- * updated with new values. It can be thought of as {@link Update} for
- * <strong>all</strong> properties of a record.
- * <p>
- * The only distinction to a regular {@link Update} is that if Replace is used
- * and the associated {@code where} expression yields no result, a
- * <strong>new</strong> record will be insterted into Storage.
- * <p>
- * The result of this operation is undefined if the {@code where} expression
- * matches more than one record in storage.
- *
- * @see Add
- * @see Remove
- * @see Update
- */
-public interface Replace<T extends Pojo> extends DataModifyingStatement<T> {
-
-    /**
-     * Sets a field in a found record to the specified value. If the same key is
-     * set more than once, the latest value overrides the former value for that
-     * key.
-     * 
-     * @param key
-     *            the name of the field to update.
-     * @param value
-     *            the value with which to update the field.
-     */
-    void set(String key, Object value);
-
-    /**
-     * Specifies what criteria to use to find the record to replace
-     */
-    void where(Expression expression);
-
-    /**
-     * Applies this {@code Replace} operation to the storage.
-     *
-     * @throws StorageException If the operation fails
-     */
-    int apply();
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/SecureQueuedStorage.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 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.shared.perflog.PerformanceLogFormatter;
-
-/**
- * Secure version of {@link QueuedStorage}. I.e. its delegate is an instance of
- * {@link SecureStorage}.
- *
- * @see SecureStorage
- * @see QueuedStorage
- */
-public final class SecureQueuedStorage extends QueuedStorage implements SecureStorage {
-
-    public SecureQueuedStorage(SecureStorage storage, PerformanceLogFormatter logger) {
-        super(storage, logger);
-    }
-    
-    public SecureQueuedStorage(SecureStorage storage) {
-        this(storage, null);
-    }
-    
-    @Override
-    public AuthToken generateToken(String actionName) throws StorageException {
-        return ((SecureStorage)delegate).generateToken(actionName);
-    }
-
-    @Override
-    public boolean verifyToken(AuthToken token, String actionName) {
-        return ((SecureStorage)delegate).verifyToken(token, actionName);
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/SecureStorage.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Provides authentication service to the command channel API.
- *
- * The protocol works as follows:
- *
- * <ol>
- * <li> The client asks the SecureStorage for an authentication token using {@link #generateToken(String)}.
- *      This should happen over an authenticated and secured connection, thus authenticating the client
- *      in the storage. The returned AuthToken will carry a client-token (that has been generated by the
- *      client) and an auth-token (generated by the storage). If authentication fails at this stage
- *      (e.g. because the client does not have the necessary privileges/roles), a StorageException is
- *      thrown.
- * </li>
- * <li> The AuthToken (both parts, client and auth token), are sent together with the command request to
- *      the command receiver (usually an agent).
- * </li>
- * <li> The agent takes the tokens, and calls the SecureStorage's {@link #verifyToken(AuthToken)} to
- *      verify the validity of the tokens. Again, this needs to happen through an authenticated and
- *      secured connection, thus authenticating the receiver. The storage verifies that it generated
- *      the same token for an authenticated client before, and replies with true if it succeeds, and
- *      false otherwise.
- */
-public interface SecureStorage extends Storage {
-
-    /**
-     * Generates a token in the storage that can be used to authenticate cmd
-     * channel requests.
-     * 
-     * @param actionName
-     *            A unique name of the type of action to be performed.
-     * 
-     * @throws StorageException
-     *             if authentication fails at this point
-     */
-    AuthToken generateToken(String actionName) throws StorageException;
-
-    /**
-     * Verifies the specified token and action in the storage.
-     * 
-     * @param actionName
-     *            A unique name of the type of action to be performed. This
-     *            action name is used during verification. This means if
-     *            verification succeeds, the given action name can be trusted
-     *            and may be used for authorization checks.
-     * @param token The token to be verified.
-     * 
-     * @return <code>true</code> if authentication succeeded, <code>false</code>
-     *         otherwise
-     */
-    boolean verifyToken(AuthToken token, String actionName);
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Statement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Implementations of this interface represent operations on storage. This
- * includes queries and statements manipulating data.
- * 
- * @see BackingStorage
- * @see Query
- * @see Update
- * @see Replace
- * @see Add
- * @see Remove
- */
-public interface Statement<T extends Pojo> {
-
-    /**
-     * Produces a copy of this statement as if it was just created with the
-     * corresponding factory method in {@link BackingStorage}.
-     * 
-     * @return A new raw instance of this statement.
-     */
-    Statement<T> getRawDuplicate();
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/StatementDescriptor.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright 2012-2017 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.Objects;
-
-import com.redhat.thermostat.storage.model.Pojo;
-
-public final class StatementDescriptor<T extends Pojo> {
-    
-    private final Category<T> category;
-    private final String desc;
-    
-    public StatementDescriptor(Category<T> category, String desc) {
-        this.category = Objects.requireNonNull(category);
-        this.desc = Objects.requireNonNull(desc);
-    }
-
-    /**
-     * Describes this statement for preparation. For example:
-     * 
-     * <pre>
-     * QUERY host-info WHERE 'agentId' = ?s LIMIT 1
-     * </pre>
-     * 
-     * @return The statement descriptor.
-     */
-    public String getDescriptor() {
-        return desc;
-    }
-    
-    public Category<T> getCategory() {
-        return category;
-    }
-    
-    @Override
-    public String toString() {
-        return desc;
-    }
-    
-    @Override
-    public int hashCode() {
-        /*
-         * Note that category's hash code gets generated on de-facto-immutable
-         * values. Hence, it is safe to use it here.
-         */
-        return Objects.hash(desc, category);
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof StatementDescriptor)) {
-            return false;
-        }
-        @SuppressWarnings("rawtypes")
-        StatementDescriptor o = (StatementDescriptor)other;
-        return desc.equals(o.desc)
-                && category.equals(o.category);
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/StatementExecutionException.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-
-/**
- * Exception thrown if something was wrong with a {@link PreparedStatement}
- * and it was attempted to execute it.
- *
- */
-@SuppressWarnings("serial")
-public class StatementExecutionException extends Exception {
-
-    public StatementExecutionException(Throwable cause) {
-        super(cause);
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012-2017 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.io.InputStream;
-
-import com.redhat.thermostat.annotations.Service;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/**
- * A storage can be used to store, query, update and remove data.
- * Implementations may use memory, a file, some database or even a network
- * server as the backing store.
- */
-@Service
-public interface Storage {
-
-    /**
-     * Register the category into the Storage. A Category must be registered
-     * into storage (normally handled by the Category's constructor) before it
-     * can be used.
-     *
-     * @throws StorageException
-     *             If the category can not be registered for some reason
-     */
-    void registerCategory(Category<?> category);
-    
-    /**
-     * Prepares the given statement for execution.
-     * 
-     * @param desc
-     *            The statement descriptor to prepare.
-     * @return A {@link PreparedStatement} if the given statement descriptor was
-     *         known and did not fail to parse.
-     * @throws DescriptorParsingException
-     *             If the descriptor string failed to parse.
-     * @throws IllegalDescriptorException
-     *             If storage refused to prepare a statement descriptor for
-     *             security reasons.
-     */
-    <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc)
-            throws DescriptorParsingException;
-
-    /**
-     * Returns the Connection object that may be used to manage connections
-     * to this Storage. Subsequent calls to this method should return
-     * the same Connection.
-     * @return the Connection for this Storage
-     */
-    Connection getConnection();
-
-    /**
-     * Drop all data related to the specified agent.
-     *
-     * @param agentId
-     *            The id of the agent
-     * @throws StorageException
-     *            If the purge operation fails
-     */
-    void purge(String agentId);
-
-    /**
-     * Save the contents of the input stream as the given name.
-     *
-     * @param filename
-     *            The name to save this data stream as. This must be unique
-     *            across all machines and processes using the storage or it will
-     *            overwrite data.
-     * @param data
-     *            The data to save.
-     * @param listener
-     *            The listener is notified upon various events related to the
-     *            saving of the file. The types of events are defined by
-     *            {@link SaveFileListener.EventTypes} Callers are responsible
-     *            for handling events appropriately via this listener, including
-     *            closing the InputStream when receiving an event indicating
-     *            that Storage is no longer using it (such as SAVE_COMPLETE or
-     *            EXCEPTION_OCCURRED).
-     */
-    void saveFile(String filename, InputStream data, SaveFileListener listener);
-
-    /**
-     * Load the file with the given name and return the data as an InputStream.
-     *
-     * @return the data as an {@link InputStream} or {@code null} if not found.
-     *
-     * @throws StorageException
-     *            May be thrown if the load operation fails
-     */
-    InputStream loadFile(String filename);
-
-    /**
-     * Shutdown the storage
-     *
-     * @throws StorageException
-     *            If the shutdown operation fails
-     */
-    void shutdown();
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/StorageProvider.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright 2012-2017 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.shared.config.SSLConfiguration;
-import com.redhat.thermostat.storage.config.StartupConfiguration;
-
-/**
- * Factory for creating a new {@link Storage} instance.
- * 
- */
-public interface StorageProvider {
-
-    /**
-     * Creates a new {@link Storage}.
-     * 
-     * @return The new instance.
-     */
-    Storage createStorage();
-
-    /**
-     * Sets the to-be-used configuration of this StorageProvider. Called prior
-     * {@link StorageProvider#canHandleProtocol()}.
-     * 
-     * @param config
-     * @param sslConf
-     */
-    void setConfig(String url, StorageCredentials creds, SSLConfiguration sslConf);
-
-    /**
-     * Method which determines if this StorageProvider can handle the given
-     * protocol as set via
-     * {@link StorageProvider#setConfig(StartupConfiguration)}.
-     * 
-     * <br/>
-     * <br/>
-     * <strong>Pre:</strong> Configuration has been set via
-     * {@link StorageProvider#setConfig(StartupConfiguration)}.
-     * 
-     * @return true if this StorageProvider can handle the protocol prefix of
-     *         the given StartupConfiguration. I.e.
-     *         {@link StorageProvider#createStorage()} can be safely called
-     *         given this config. false otherwise.
-     */
-    boolean canHandleProtocol();
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012-2017 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;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Updates properties of a record in storage.
- * 
- * @see Add
- * @see Replace
- * @see Remove
- */
-public interface Update<T extends Pojo> extends DataModifyingStatement<T> {
-
-    /**
-     * Given a boolean expression, this method specifies a where condition for
-     * this update operation. If an update is issued for which no entry can be
-     * found (i.e. the where-clause yields no results), a
-     * <code>StorageException</code> may get thrown.
-     * 
-     * @param expr
-     *            A boolean expression.
-     */
-    void where(Expression expr);
-
-    /**
-     * Sets a field in a found record to the specified value. If the same key is
-     * set more than once, the latest value overrides the former value for that
-     * key.
-     * 
-     * @param key
-     *            the name of the field to update.
-     * @param value
-     *            the value with which to update the field.
-     */
-    void set(String key, Object value);
-
-    /**
-     * Applies this update operation.
-     *
-     * @throws StorageException if this operation fails
-     */
-    int apply();
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetter.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetter.java	Fri May 19 11:58:05 2017 +0200
@@ -39,11 +39,9 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
 
-public class VmBoundaryPojoGetter<T extends TimeStampedPojo> extends AbstractDao {
+public class VmBoundaryPojoGetter<T extends TimeStampedPojo>  {
 
     // QUERY %s WHERE 'agentId' = ?s AND \
     //                        'vmId' = ?s \
@@ -67,13 +65,11 @@
 
     private static final Logger logger = LoggingUtils.getLogger(VmBoundaryPojoGetter.class);
 
-    private final Storage storage;
     private final Category<T> cat;
     private final String queryNewest;
     private final String queryOldest;
 
-    public VmBoundaryPojoGetter(Storage storage, Category<T> cat) {
-        this.storage = storage;
+    public VmBoundaryPojoGetter(Category<T> cat) {
         this.cat = cat;
         this.queryNewest = String.format(DESC_NEWEST_VM_STAT, cat.getName());
         this.queryOldest = String.format(DESC_OLDEST_VM_STAT, cat.getName());
@@ -104,14 +100,7 @@
     }
 
     private T runAgentAndVmIdQuery(final String vmId, final String agentId, final String descriptor) {
-        return executeQuery(new AbstractDaoQuery<T>(storage, cat, descriptor) {
-            @Override
-            public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-                preparedStatement.setString(0, agentId);
-                preparedStatement.setString(1, vmId);
-                return preparedStatement;
-            }
-        }).head();
+        return null;
     }
 
     //Package private for testing
@@ -124,7 +113,6 @@
         return queryOldest;
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Fri May 19 11:58:05 2017 +0200
@@ -40,8 +40,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
 
 /**
@@ -49,7 +47,7 @@
  *
  * @see VmTimeIntervalPojoListGetter
  */
-public class VmLatestPojoListGetter<T extends TimeStampedPojo> extends AbstractDao {
+public class VmLatestPojoListGetter<T extends TimeStampedPojo> {
 
     public static final String VM_LATEST_QUERY_FORMAT = "QUERY %s WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s AND '"
@@ -58,12 +56,10 @@
             + Key.TIMESTAMP.getName() + "' DSC";
     private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class);
 
-    private final Storage storage;
     private final Category<T> cat;
     private final String queryLatest;
 
-    public VmLatestPojoListGetter(Storage storage, Category<T> cat) {
-        this.storage = storage;
+    public VmLatestPojoListGetter(Category<T> cat) {
         this.cat = cat;
         this.queryLatest = String.format(VM_LATEST_QUERY_FORMAT, cat.getName());
     }
@@ -77,15 +73,7 @@
     }
 
     public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since) {
-        return executeQuery(new AbstractDaoQuery<T>(storage, cat, queryLatest) {
-            @Override
-            public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-                preparedStatement.setString(0, agentId.get());
-                preparedStatement.setString(1, vmId.get());
-                preparedStatement.setLong(2, since);
-                return preparedStatement;
-            }
-        }).asList();
+        return null;
     }
 
     // package private for tests
@@ -93,7 +81,6 @@
         return queryLatest;
     }
 
-    @Override
     public Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetter.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetter.java	Fri May 19 11:58:05 2017 +0200
@@ -40,8 +40,6 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
 
 /**
@@ -50,7 +48,7 @@
  *
  * @see VmLatestPojoListGetter
  */
-public class VmTimeIntervalPojoListGetter<T extends TimeStampedPojo> extends AbstractDao {
+public class VmTimeIntervalPojoListGetter<T extends TimeStampedPojo>  {
 
     // The query for VmTimeIntervalPojoListGetter should query for since <= timestamp < to
     // in order not to miss data for multiple consecutive queries of the form [a, b), [b, c), ...
@@ -65,12 +63,10 @@
 
     private static final Logger logger = LoggingUtils.getLogger(VmTimeIntervalPojoListGetter.class);
 
-    private final Storage storage;
     private final Category<T> cat;
     private final String query;
 
-    public VmTimeIntervalPojoListGetter(Storage storage, Category<T> cat) {
-        this.storage = storage;
+    public VmTimeIntervalPojoListGetter(Category<T> cat) {
         this.cat = cat;
         this.query = String.format(VM_INTERVAL_QUERY_FORMAT, cat.getName());
     }
@@ -84,16 +80,7 @@
     }
 
     public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since, final long to) {
-        return executeQuery(new AbstractDaoQuery<T>(storage, cat, query) {
-            @Override
-            public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-                preparedStatement.setString(0, agentId.get());
-                preparedStatement.setString(1, vmId.get());
-                preparedStatement.setLong(2, since);
-                preparedStatement.setLong(3, to);
-                return preparedStatement;
-            }
-        }).asList();
+        return null;
     }
 
     // package private for tests
@@ -101,7 +88,6 @@
         return query;
     }
 
-    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDao.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.model.Pojo;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Logger;
-
-import static com.redhat.thermostat.storage.internal.dao.LoggingUtil.logDescriptorParsingException;
-import static com.redhat.thermostat.storage.internal.dao.LoggingUtil.logStatementExecutionException;
-
-public abstract class AbstractDao {
-
-    final <T extends Pojo> PreparedStatement<T> getCustomizedPreparedStatement(DaoOperation<T> daoOperation) throws DescriptorParsingException {
-        PreparedStatement<T> preparedStatement = daoOperation.getStorage()
-                .prepareStatement(daoOperation.getStatementDescriptor());
-        return daoOperation.customize(preparedStatement);
-    }
-
-    protected final <T extends Pojo> StatementResult<T> executeStatement(DaoStatement<T> daoOperation) {
-        List<Exception> exceptions = new ArrayList<>();
-        try {
-            getCustomizedPreparedStatement(daoOperation).execute();
-        } catch (DescriptorParsingException e) {
-            logDescriptorParsingException(getLogger(), daoOperation.getStatementDescriptor(), e);
-            exceptions.add(e);
-        } catch (StatementExecutionException e) {
-            logStatementExecutionException(getLogger(), daoOperation.getStatementDescriptor(), e);
-            exceptions.add(e);
-        }
-
-        StatementResult<T> statementResult = new StatementResult<>();
-        statementResult.addExceptions(exceptions);
-        return statementResult;
-    }
-
-    protected final <T extends Pojo> QueryResult<T> executeQuery(DaoOperation<T> daoOperation) {
-        List<Exception> exceptions = new ArrayList<>();
-        Cursor<T> cursor = getEmptyResultCursor();
-        try {
-            cursor = getCustomizedPreparedStatement(daoOperation).executeQuery();
-        } catch (DescriptorParsingException e) {
-            logDescriptorParsingException(getLogger(), daoOperation.getStatementDescriptor(), e);
-            exceptions.add(e);
-        } catch (StatementExecutionException e) {
-            logStatementExecutionException(getLogger(), daoOperation.getStatementDescriptor(), e);
-            exceptions.add(e);
-        }
-
-        QueryResult<T> queryResult = new QueryResult<>(cursor);
-        queryResult.addExceptions(exceptions);
-        return queryResult;
-    }
-
-    protected abstract Logger getLogger();
-
-    protected static <T extends Pojo> Cursor<T> getEmptyResultCursor() {
-        return new Cursor<T>() {
-            @Override
-            public void setBatchSize(int n) throws IllegalArgumentException {
-            }
-
-            @Override
-            public int getBatchSize() {
-                return 0;
-            }
-
-            @Override
-            public boolean hasNext() {
-                return false;
-            }
-
-            @Override
-            public T next() {
-                return null;
-            }
-
-            @Override
-            public void remove() {
-                throw new UnsupportedOperationException();
-            }
-        };
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoOperation.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public abstract class AbstractDaoOperation<T extends Pojo> implements DaoOperation<T> {
-
-    protected final Storage storage;
-    protected final StatementDescriptor<T> statementDescriptor;
-
-    public AbstractDaoOperation(Storage storage, Category<T> category, String descriptor) {
-        this.storage = storage;
-        this.statementDescriptor = new StatementDescriptor<>(category, descriptor);
-    }
-
-    @Override
-    public Storage getStorage() {
-        return storage;
-    }
-
-    @Override
-    public StatementDescriptor<T> getStatementDescriptor() {
-        return statementDescriptor;
-    }
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoOperationResult.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.model.Pojo;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public abstract class AbstractDaoOperationResult<T extends Pojo> implements DaoOperationResult<T> {
-
-    private final List<Exception> exceptions = new ArrayList<>();
-
-    @Override
-    public void addException(Exception e) {
-        exceptions.add(e);
-    }
-
-    @Override
-    public void addExceptions(Iterable<Exception> exceptions) {
-        for (Exception e : exceptions) {
-            addException(e);
-        }
-    }
-
-    @Override
-    public boolean hasExceptions() {
-        return !exceptions.isEmpty();
-    }
-
-    @Override
-    public List<Exception> getExceptions() {
-        return Collections.unmodifiableList(exceptions);
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoQuery.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public abstract class AbstractDaoQuery<T extends Pojo> extends AbstractDaoOperation<T> implements DaoQuery<T> {
-
-    public AbstractDaoQuery(Storage storage, Category<T> category, String descriptor) {
-        super(storage, category, descriptor);
-    }
-
-    @Override
-    public Cursor<T> execute(PreparedStatement<T> preparedStatement) throws DescriptorParsingException, StatementExecutionException {
-        return preparedStatement.executeQuery();
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AbstractDaoStatement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public abstract class AbstractDaoStatement<T extends Pojo> extends AbstractDaoOperation<T> implements DaoStatement<T> {
-
-    public AbstractDaoStatement(Storage storage, Category<T> category, String descriptor) {
-        super(storage, category, descriptor);
-    }
-
-    @Override
-    public void execute(PreparedStatement<T> preparedStatement) throws DescriptorParsingException, StatementExecutionException {
-        preparedStatement.execute();
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/BaseCountable.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.AggregateCount;
-
-/**
- * This class provides generic functionality for performing an aggregate count query.
- */
-public class BaseCountable extends AbstractDao {
-    
-    private static final int ERROR_COUNT_RESULT = -1;
-    private static final Logger logger = LoggingUtils.getLogger(BaseCountable.class);
-
-    /**
-     * Performs an aggregate count query as described by the given descriptor.
-     * 
-     * @param storage the storage to use for preparing the descriptor.
-     * @param category the query category.
-     * @param descriptor the query descriptor.
-     * @return -1 if execution failed for some reason, the actual count of the
-     *         query results if successful.
-     */
-    protected long getCount(Storage storage, Category<AggregateCount> category, String descriptor) {
-        QueryResult<AggregateCount> result = executeQuery(new SimpleDaoQuery<>(storage, category, descriptor));
-        AggregateCount count = result.head();
-        if (count == null || result.hasExceptions()) {
-            return ERROR_COUNT_RESULT;
-        } else {
-            return count.getCount();
-        }
-    }
-
-    @Override
-    protected Logger getLogger() {
-        return logger;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/DaoOperation.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;/*
- * Copyright 2012-2015 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.
- */
-
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public interface DaoOperation<T extends Pojo> {
-
-    PreparedStatement<T> customize(PreparedStatement<T> preparedStatement);
-
-    Storage getStorage();
-
-    StatementDescriptor<T> getStatementDescriptor();
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/DaoQuery.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;/*
- * Copyright 2012-2015 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.
- */
-
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public interface DaoQuery<T extends Pojo> extends DaoOperation<T> {
-
-    Cursor<T> execute(PreparedStatement<T> preparedStatement)
-            throws DescriptorParsingException, StatementExecutionException;
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/DaoStatement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;/*
- * Copyright 2012-2015 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.
- */
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public interface DaoStatement<T extends Pojo> extends DaoOperation<T> {
-
-    void execute(PreparedStatement<T> preparedStatement)
-            throws DescriptorParsingException, StatementExecutionException;
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/QueryResult.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.common.utils.IteratorUtils;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.model.Pojo;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-public class QueryResult<T extends Pojo> extends AbstractDaoOperationResult<T> {
-
-    private final List<T> contents;
-
-    public QueryResult(Cursor<T> cursor) {
-        contents = IteratorUtils.asList(cursor);
-    }
-
-    public List<T> asList() {
-        return contents;
-    }
-
-    public T head() {
-        if (contents.isEmpty()) {
-            return null;
-        } else {
-            return contents.get(0);
-        }
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return contents.iterator();
-    }
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/SimpleDaoQuery.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public class SimpleDaoQuery<T extends Pojo> extends AbstractDaoQuery<T> {
-
-    public SimpleDaoQuery(Storage storage, Category<T> category, String descriptor) {
-        super(storage, category, descriptor);
-    }
-
-    @Override
-    public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-        return preparedStatement;
-    }
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/SimpleDaoStatement.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public class SimpleDaoStatement<T extends Pojo> extends AbstractDaoStatement<T> {
-
-    public SimpleDaoStatement(Storage storage, Category<T> category, String descriptor) {
-        super(storage, category, descriptor);
-    }
-
-    @Override
-    public PreparedStatement<T> customize(PreparedStatement<T> preparedStatement) {
-        return preparedStatement;
-    }
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/StatementResult.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.model.Pojo;
-
-import java.util.Collections;
-import java.util.Iterator;
-
-public class StatementResult<T extends Pojo> extends AbstractDaoOperationResult<T> {
-
-    @Override
-    public Iterator<T> iterator() {
-        return Collections.<T>emptyList().iterator();
-    }
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/CountingDecorator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-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 java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.perflog.PerformanceLogFormatter;
-import com.redhat.thermostat.shared.perflog.PerformanceLogFormatter.LogTag;
-import com.redhat.thermostat.storage.core.QueuedStorage;
-
-/**
- * Decorator for ExecutorService's based queued storage. Allows for inspecting
- * and logging the queue size.
- *
- * @see QueuedStorage
- */
-public class CountingDecorator implements ExecutorService {
-
-    private static final String QUEUE_SIZE_PREFIX = "Q_SIZE";
-    private static final String QUEUE_SIZE_FORMAT = QUEUE_SIZE_PREFIX + " %s";
-    private static final Logger logger = LoggingUtils.getLogger(CountingDecorator.class);
-    private final LogTag logTag;
-    private final PerformanceLogFormatter perfLogFormatter;
-    private final ExecutorService decoratee;
-    private final AtomicLong queueLength;
-    
-    /**
-     * 
-     * @param decoratee
-     *            The executor service to decorate.
-     * @param perfLogFormatter
-     *            The log formatter to use for logged messages.
-     * @param logTag The log tag to use when logging messages.
-     */
-    public CountingDecorator(ExecutorService decoratee, PerformanceLogFormatter perfLogFormatter, LogTag logTag) {
-        this.decoratee = Objects.requireNonNull(decoratee);
-        this.perfLogFormatter = Objects.requireNonNull(perfLogFormatter);
-        this.logTag = logTag;
-        this.queueLength = new AtomicLong();
-    }
-    
-    @Override
-    public void execute(final Runnable command) {
-        queueLength.incrementAndGet();
-        decoratee.execute(new Runnable() {
-
-            @Override
-            public void run() {
-                command.run();
-                queueLength.decrementAndGet();
-            }
-            
-        });
-        String msg = String.format(QUEUE_SIZE_FORMAT, queueLength.get());
-        logger.log(LoggingUtils.LogLevel.PERFLOG.getLevel(), perfLogFormatter.format(logTag, msg));
-    }
-
-    @Override
-    public void shutdown() {
-        decoratee.shutdown();
-    }
-
-    @Override
-    public List<Runnable> shutdownNow() {
-        return decoratee.shutdownNow();
-    }
-
-    @Override
-    public boolean isShutdown() {
-        return decoratee.isShutdown();
-    }
-
-    @Override
-    public boolean isTerminated() {
-        return decoratee.isTerminated();
-    }
-
-    @Override
-    public boolean awaitTermination(long timeout, TimeUnit unit)
-            throws InterruptedException {
-        return decoratee.awaitTermination(timeout, unit);
-    }
-
-    @Override
-    public <T> Future<T> submit(Callable<T> task) {
-        return decoratee.submit(task);
-    }
-
-    @Override
-    public <T> Future<T> submit(Runnable task, T result) {
-        return decoratee.submit(task, result);
-    }
-
-    @Override
-    public Future<?> submit(Runnable task) {
-        return decoratee.submit(task);
-    }
-
-    @Override
-    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
-            throws InterruptedException {
-        return decoratee.invokeAll(tasks);
-    }
-
-    @Override
-    public <T> List<Future<T>> invokeAll(
-            Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
-            throws InterruptedException {
-        return decoratee.invokeAll(tasks, timeout, unit);
-    }
-
-    @Override
-    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
-            throws InterruptedException, ExecutionException {
-        return decoratee.invokeAny(tasks);
-    }
-
-    @Override
-    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
-            long timeout, TimeUnit unit) throws InterruptedException,
-            ExecutionException, TimeoutException {
-        return decoratee.invokeAny(tasks, timeout, unit);
-    }
-    
-    public long getQueueLength() {
-        return queueLength.get();
-    }
-
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/DbServiceImpl.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,300 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.storage.core.Connection;
-import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
-import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
-import com.redhat.thermostat.storage.core.ConnectionException;
-import com.redhat.thermostat.storage.core.DbService;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-import com.redhat.thermostat.storage.core.StorageException;
-import com.redhat.thermostat.storage.core.StorageProvider;
-
-public class DbServiceImpl implements DbService {
-    
-    private static Logger logger = LoggingUtils.getLogger(DbServiceImpl.class);
-    @SuppressWarnings("rawtypes")
-    private ServiceRegistration dbServiceReg;
-    @SuppressWarnings("rawtypes")
-    private ServiceRegistration storageReg;
-    
-    private Storage storage;
-    private BundleContext context;
-    private String dbUrl;
-    private String userName;
-    
-    DbServiceImpl(String dbUrl, StorageCredentials creds, SSLConfiguration sslConf) throws StorageException {
-        BundleContext context = FrameworkUtil.getBundle(DbService.class).getBundleContext();
-        init(context, dbUrl, creds, sslConf);
-    }
-
-    // for testing
-    DbServiceImpl(BundleContext context, String dbUrl, StorageCredentials creds, SSLConfiguration sslConf) {
-        init(context, dbUrl, creds, sslConf);
-    }
-    
-    // For testing. Injects custom storage.
-    DbServiceImpl(BundleContext context, Storage storage, StorageCredentials creds, SSLConfiguration sslConf) {
-        this.context = context;
-        this.storage = storage;
-    }
-    
-    private void init(BundleContext context, String dbUrl, StorageCredentials creds, SSLConfiguration sslConf) {
-        Storage storage = createStorage(context, dbUrl, creds, sslConf);
-        this.storage = storage;
-        this.context = context;
-        this.dbUrl = dbUrl;
-    }
-
-    public void connect() throws ConnectionException {
-        // Storage and DbService must not be registered
-        // as service
-        ensureConnectPreCondition();
-        try {
-            // connection needs to be synchronous, otherwise there is no
-            // way to guarantee the postcondition if there's a delayed exception
-            // during connection handling.
-            doSynchronousConnect();
-        } catch (Exception cause) {
-            throw new ConnectionException(cause);
-        }
-        // Connection didn't throw an exception. Now it is safe to register
-        // services for general consumption.
-        dbServiceReg = context.registerService(DbService.class, this, null);
-        storageReg = context.registerService(Storage.class.getName(), this.storage, null);
-    }
-    
-    private void doSynchronousConnect() throws ConnectionException {
-        CountDownLatch latch = new CountDownLatch(1);
-        SynchronousConnectionListener listener = new SynchronousConnectionListener(
-                latch, ConnectionStatus.CONNECTED);
-        // Install listener in order to ensure connection is synchronous.
-        addConnectionListener(listener);
-        Connection connection = this.storage.getConnection();
-        connection.connect();
-        try {
-            // Wait for connection to finish.
-            // The synchronous connection listener gets removed once connection
-            // has finished.
-            latch.await();
-            // Grab username after connection completes
-            this.userName = connection.getUsername();
-        } catch (InterruptedException e) {
-            logger.log(Level.WARNING, e.getMessage(), e);
-        }
-        if (!listener.successful) {
-            throw new ConnectionException();
-        }
-    }
-
-    public void disconnect() throws ConnectionException {
-        // DbService and Storage must be registered as service at this point
-        ensureDisconnectPrecondition();
-        try {
-            doSyncronousDisconnect();
-        } catch (Exception cause) {
-            throw new ConnectionException(cause);
-        }
-        storageReg.unregister();
-        dbServiceReg.unregister();
-    }
-    
-    private void doSyncronousDisconnect() {
-        CountDownLatch latch = new CountDownLatch(1);
-        SynchronousConnectionListener listener = new SynchronousConnectionListener(
-                latch, ConnectionStatus.DISCONNECTED);
-        // Install listener in order to ensure connection is synchronous.
-        addConnectionListener(listener);
-        this.storage.getConnection().disconnect();
-        try {
-            // Wait for disconnect to finish.
-            // The synchronous connection listener gets removed once connection
-            // has finished.
-            latch.await();
-            this.userName = Connection.UNSET_USERNAME;
-        } catch (InterruptedException e) {
-            logger.log(Level.WARNING, e.getMessage(), e);
-        }
-        if (!listener.successful) {
-            throw new ConnectionException();
-        }
-    }
-
-    @Override
-    public String getConnectionUrl() {
-        return dbUrl;
-    }
-
-    @Override
-    public String getUserName() {
-        return this.userName;
-    }
-
-    /**
-     * Factory method for creating a DbService instance.
-     *
-     * @param dbUrl The storage url to use
-     * @param creds The storage credentials to use
-     * @param sslConf The SSL configuration to use
-     * @return a DbService instance
-     * @throws StorageException if no storage provider exists for the given {@code dbUrl}.
-     */
-    public static DbService create(String dbUrl, StorageCredentials creds, SSLConfiguration sslConf) throws StorageException {
-        return new DbServiceImpl(dbUrl, creds, sslConf);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private void ensureDisconnectPrecondition() {
-        ServiceReference dbServiceReference = context
-                .getServiceReference(DbService.class);
-        ServiceReference storageReference = context
-                .getServiceReference(Storage.class);
-        if (dbServiceReference == null || storageReference == null) {
-            throw new IllegalStateException(
-                    "DbService or Storage not registered as service when "
-                            + "trying to disconnect");
-        }
-    }
-
-    @SuppressWarnings("rawtypes")
-    private void ensureConnectPreCondition() {
-        ServiceReference dbServiceReference = context
-                .getServiceReference(DbService.class);
-        ServiceReference storageReference = context
-                .getServiceReference(Storage.class);
-        if (dbServiceReference != null || storageReference != null) {
-            throw new IllegalStateException(
-                    "DbService or Storage already registered as service when "
-                            + "trying to connect");
-        }
-    }
-
-    private static Storage createStorage(BundleContext context, String dbUrl, StorageCredentials creds, SSLConfiguration sslConf) throws StorageException {
-        StorageProvider prov = getStorageProvider(context, dbUrl, creds, sslConf);
-        if (prov == null) {
-            // no suitable provider found
-            throw new StorageException("No storage found for URL " + dbUrl);
-        }
-        return prov.createStorage();
-    }
-    
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private static StorageProvider getStorageProvider(BundleContext context, String url, StorageCredentials creds, SSLConfiguration sslConf) {
-        try {
-            ServiceReference[] refs = context.getServiceReferences(StorageProvider.class.getName(), null);
-            if (refs == null) {
-                throw new StorageException("No storage provider available");
-            }
-            for (int i = 0; i < refs.length; i++) {
-                StorageProvider prov = (StorageProvider) context.getService(refs[i]);
-                prov.setConfig(url, creds, sslConf);
-                if (prov.canHandleProtocol()) {
-                    return prov;
-                }
-                else {
-                    context.ungetService(refs[i]);
-                }
-            }
-        } catch (InvalidSyntaxException e) {
-            throw new AssertionError("Bad filter used to get StorageProviders", e);
-        }
-        return null;
-    }
-
-    @Override
-    public void addConnectionListener(ConnectionListener listener) {
-        storage.getConnection().addListener(listener);
-    }
-
-    @Override
-    public void removeConnectionListener(ConnectionListener listener) {
-        storage.getConnection().removeListener(listener);
-    }
-    
-    class SynchronousConnectionListener implements ConnectionListener {
-
-        CountDownLatch latch;
-        boolean successful = false;
-        ConnectionStatus expectedType;
-        
-        public SynchronousConnectionListener(CountDownLatch latch, ConnectionStatus expectedType) {
-            this.latch = latch;
-            this.expectedType = expectedType;
-        }
-        
-        @Override
-        public void changed(ConnectionStatus newStatus) {
-            switch (newStatus) {
-            case CONNECTED: {
-                successful = (expectedType == ConnectionStatus.CONNECTED);
-                latch.countDown();
-                removeConnectionListener(this);
-                break;
-            }
-            case FAILED_TO_CONNECT: {
-                latch.countDown();
-                removeConnectionListener(this);
-                break;
-            }
-            case DISCONNECTED: {
-                successful = (expectedType == ConnectionStatus.DISCONNECTED);
-                latch.countDown();
-                removeConnectionListener(this);
-            }
-            default: {
-                // nothing
-            }
-            }
-        }
-        
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/LoggingUtil.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.dao;
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.model.Pojo;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public final class LoggingUtil {
-
-    private LoggingUtil() {}
-
-    public static <T extends Pojo> void logDescriptorParsingException(Logger logger, StatementDescriptor<T> desc, DescriptorParsingException e) {
-        logQueryStatementException(logger, Level.SEVERE, desc, e);
-    }
-
-    public static <T extends Pojo> void logStatementExecutionException(Logger logger, StatementDescriptor<T> desc, StatementExecutionException e) {
-        logQueryStatementException(logger, Level.SEVERE, desc, e);
-    }
-
-    static <T extends Pojo> void logQueryStatementException(Logger logger, Level level, StatementDescriptor<T> desc, Exception e) {
-        logger.log(level, "Executing query/statement '" + desc + "' failed!", e);
-    }
-
-}
\ No newline at end of file
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/AbstractUnfinished.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-/**
- * Abstract superclass for unfinished nodes (i.e. nodes in the prepared
- * statements parse tree which need to be patched with their real values).
- * 
- */
-abstract class AbstractUnfinished implements Unfinished {
-
-    @Override
-    public boolean equals(Object other) {
-        if (other == null) {
-            return false;
-        }
-        if (!(other instanceof Unfinished)) {
-            return false;
-        }
-        Unfinished o = (Unfinished)other;
-        return getParameterIndex() == o.getParameterIndex();
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(getParameterIndex());
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/BasicDescriptorParser.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,859 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-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;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
-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.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
-
-/**
- * A parser for the string representation of {@link StatementDescriptor}s.
- * Tokens have to be separated by whitespace.
- * 
- * This parser implements the following simple grammar for statement descriptors.
- * It supports the following statement types:
- * <ul>
- * <li>QUERY (read)</li>
- * <li>QUERY-COUNT (read)</li>
- * <li>ADD (write)</li>
- * <li>UPDATE (write)</li>
- * <li>REPLACE (write)</li>
- * <li>REMOVE (write)</li>
- * </ul>
- * 
- * <p><strong>Grammar:</strong></p>
- * <pre>
- * statementDesc := statementType category setList suffix
- * statementType := 'QUERY' | 'QUERY-COUNT' |
- *                  'ADD' | 'REPLACE' | 'UPDATE' |
- *                  'REMOVE'
- * category      := string
- * setList       := 'SET' setValues | \empty
- * setValues     := valuePair valueList
- * valuePair     := term '=' term
- * valueList     := ',' setValues | \empty
- * suffix        := 'WHERE' where |
- *                  'SORT' sortCond |
- *                  'LIMIT' term | \empty
- * where         := whereExp sort limit
- * whereExp      := andCond orCond
- * orCond        := 'OR' whereExp | \empty
- * sort          := 'SORT' sortCond | \empty
- * sortCond      := sortPair sortList
- * sortPair      := term sortModifier
- * sortModifier  := 'ASC' | 'DSC'
- * sortList      := ',' sortCond | \empty
- * limit         := 'LIMIT' term | \empty
- * andCond       := condition andBody
- * andBody       := 'AND' whereExp | \empty
- * condition     := 'NOT' condition | compExp
- * compExp       := term compExpRHS
- * term          := freeParam | literal
- * freeParam     := '?s' | '?i' | '?l' | '?s[' | '?b'
- * literal       := sQuote string sQuote | int | long | boolean
- * sQuote        := \'
- * boolean       := &lt;true&gt; | &lt;false&gt;
- * int           := &lt;literal-int&gt;
- * long          := &lt;literal-long&gt;longPostFix
- * longPostFix   := 'l' | 'L'
- * string        := &lt;literal-string-value&gt;
- * compExpRHS    := '!=' term | '=' term | '&lt;=' term | '&gt;=' term | 
- *                  '&lt;' term | '&gt;' term
- * </pre>
- *
- * This implements the following logic precedence rules (in this order of
- * precedence):
- * 
- * <ol>
- *   <li>NOT</li>
- *   <li>AND</li>
- *   <li>OR</li>
- * </ol>
- * 
- * NOTE: Comparison expressions have equal precedence.
- */
-class BasicDescriptorParser<T extends Pojo> implements StatementDescriptorParser<T> {
-
-    private static final Logger logger = LoggingUtils.getLogger(BasicDescriptorParser.class);
-    private static final String TOKEN_DELIMS = " \t\r\n\f";
-    private static final short IDX_QUERY = 0;
-    private static final short IDX_ADD = 1;
-    private static final short IDX_REPLACE = 2;
-    private static final short IDX_UPDATE = 3;
-    private static final short IDX_REMOVE = 4;
-    private static final String[] KNOWN_STATEMENT_TYPES = new String[] {
-        "QUERY", "ADD", "REPLACE", "UPDATE", "REMOVE"
-    };
-    
-    // package-private for testing
-    static final String AGGREGATE_PARAM_REGEXP = "(?:\\(([a-zA-Z_]+)\\))?$";
-    private static final String QUERY_COUNT_REGEXP = "QUERY-COUNT" + AGGREGATE_PARAM_REGEXP;
-    private static final String QUERY_DISTINCT_REGEXP = "QUERY-DISTINCT" + AGGREGATE_PARAM_REGEXP;
-    private static final Pattern QUERY_COUNT_PATTERN = Pattern.compile(QUERY_COUNT_REGEXP);
-    private static final Pattern QUERY_DISTINCT_PATTERN = Pattern.compile(QUERY_DISTINCT_REGEXP);
-    private static final String SORTLIST_SEP = ",";
-    private static final String SETLIST_SEP = SORTLIST_SEP;
-    private static final String KEYWORD_SET = "SET";
-    private static final String KEYWORD_WHERE = "WHERE";
-    private static final String KEYWORD_SORT = "SORT";
-    private static final String KEYWORD_LIMIT = "LIMIT";
-    private static final String KEYWORD_ASC = "ASC";
-    private static final String KEYWORD_DSC = "DSC";
-    private static final String POJO_FREE_PARAMETER_TYPE = "?p";
-    private static final char PARAM_PLACEHOLDER = '?';
-    
-    private final String[] tokens;
-    protected final StatementDescriptor<T> desc;
-    private final BackingStorage storage;
-    private int currTokenIndex;
-    private int placeHolderCount;
-    // the parsed statement
-    private ParsedStatementImpl<T> parsedStatement;
-    protected SuffixExpression tree;
-    protected SetList setList;
-    
-    BasicDescriptorParser(BackingStorage storage, StatementDescriptor<T> desc) {
-        this.tokens = getTokens(desc.getDescriptor());
-        this.currTokenIndex = 0;
-        this.placeHolderCount = 0;
-        this.desc = desc;
-        this.storage = storage;
-    }
-    
-    private String[] getTokens(String str) {
-        StringTokenizer tokenizer = new StringTokenizer(str, TOKEN_DELIMS);
-        List<String> toks = new ArrayList<>(tokenizer.countTokens());
-        while (tokenizer.hasMoreTokens()) {
-            toks.add(tokenizer.nextToken());
-        }
-        return toks.toArray(new String[0]);
-    }
-
-    public ParsedStatement<T> parse() throws DescriptorParsingException {
-        matchStatementType();
-        matchCategory();
-        // matched so far, create the raw statement
-        createStatement();
-        this.setList = new SetList();
-        matchSetList(setList);
-        this.tree = new SuffixExpression();
-        matchSuffix();
-        if (currTokenIndex != tokens.length) {
-            throw new DescriptorParsingException("Incomplete parse of '" + desc.toString() + "'");
-        }
-        parsedStatement.setNumFreeParams(placeHolderCount);
-        parsedStatement.setSetList(setList);
-        parsedStatement.setSuffixExpression(tree);
-        return parsedStatement;
-    }
-
-    /*
-     * Match set list for DML statements.
-     */
-    private void matchSetList(final SetList setList) throws DescriptorParsingException {
-        if (tokens.length == currTokenIndex) {
-            // no set list
-            return;
-        }
-        if (tokens[currTokenIndex].equals(KEYWORD_SET)) {
-            currTokenIndex++; // SET
-            matchSetValues(setList);
-        }
-        // empty, proceed with suffix
-    }
-
-    /*
-     * Match list of values in a SET expression 
-     */
-    private void matchSetValues(SetList setList) throws DescriptorParsingException {
-        matchValuePair(setList);
-        matchValueList(setList);
-    }
-
-    /*
-     * Match more value pairs in a SET list
-     */
-    private void matchValueList(SetList setList) throws DescriptorParsingException {
-        if (currTokenIndex == tokens.length) {
-            // empty
-            return;
-        }
-        if (tokens[currTokenIndex].equals(SETLIST_SEP)) {
-            currTokenIndex++; // ,
-            matchSetValues(setList);
-        }
-    }
-
-    /*
-     * Match one pair of values in a 
-     */
-    private void matchValuePair(SetList setList) throws DescriptorParsingException {
-        SetListValue value = new SetListValue();
-        TerminalNode lval = new TerminalNode(null);
-        matchTerm(lval, true, true);
-        value.setKey(lval);
-        if (tokens[currTokenIndex].equals("=")) {
-            currTokenIndex++; // =
-        } else {
-            String msg = "Expected '=' after SET value LHS. Token was ->" + tokens[currTokenIndex] + "<-";
-            throw new DescriptorParsingException(msg);
-        }
-        TerminalNode rval = new TerminalNode(null);
-        matchTerm(rval, false, true);
-        value.setValue(rval);
-        setList.addValue(value);
-    }
-
-    /*
-     * Match optional suffixes. 
-     */
-    private void matchSuffix() throws DescriptorParsingException {
-        if (tokens.length == currTokenIndex) {
-            // no suffix
-            return;
-        }
-        if (tokens[currTokenIndex].equals(KEYWORD_WHERE)) {
-            currTokenIndex++;
-            WhereExpression expn = new WhereExpression();
-            tree.setWhereExpn(expn);
-            matchWhereExp(expn.getRoot());
-            matchSort(tree);
-            matchLimit(tree);
-        } else if (tokens[currTokenIndex].equals(KEYWORD_SORT)) {
-            // SORT token eaten up by matchSort()
-            matchSort(tree);
-            matchLimit(tree);
-        } else if (tokens[currTokenIndex].equals(KEYWORD_LIMIT)) {
-            // LIMIT token eaten up by matchLimit()
-            matchLimit(tree);
-        } else {
-            throw new DescriptorParsingException("Unexpected token: '"
-                    + tokens[currTokenIndex] + "'. Expected one of "
-                    + KEYWORD_WHERE + ", " + KEYWORD_SORT + ", " + KEYWORD_LIMIT);
-        }
-    }
-
-    private void matchLimit(SuffixExpression tree) throws DescriptorParsingException {
-        if (currTokenIndex == tokens.length) {
-            // empty
-            return;
-        } else if (currTokenIndex < tokens.length) {
-            if (tokens[currTokenIndex].equals(KEYWORD_LIMIT)) {
-                LimitExpression node = new LimitExpression();
-                tree.setLimitExpn(node);
-                currTokenIndex++;
-                matchTerm(node);
-            }
-        } else {
-            throw new DescriptorParsingException("Illegal statement descriptor: Reason LIMIT");
-        }
-    }
-
-    private void matchSort(SuffixExpression tree) throws DescriptorParsingException {
-        if (currTokenIndex < tokens.length
-                && tokens[currTokenIndex].equals(KEYWORD_SORT)) {
-            SortExpression sortExpn = new SortExpression();
-            tree.setSortExpn(sortExpn);
-            currTokenIndex++;
-            matchSortList(sortExpn);
-        } 
-        if (currTokenIndex > tokens.length) {
-            throw new DescriptorParsingException("Illegal statement descriptor.");
-        }
-        // empty
-    }
-
-    private void matchSortList(SortExpression sortExpn) throws DescriptorParsingException {
-        matchSortPair(sortExpn);
-        matchSortListPreamble(sortExpn);
-    }
-
-    private void matchSortListPreamble(SortExpression sortExpn) throws DescriptorParsingException {
-        if (currTokenIndex < tokens.length && tokens[currTokenIndex].equals(SORTLIST_SEP)) {
-            currTokenIndex++; // ',' token
-            matchSortList(sortExpn);
-        }
-    }
-
-    private void matchSortPair(SortExpression expn) throws DescriptorParsingException {
-        SortMember member = new SortMember();
-        matchTerm(member);
-        matchSortModifier(member);
-        // Add the member node to the list of the sort node
-        expn.addMember(member);
-    }
-
-    private void matchSortModifier(SortMember member) throws DescriptorParsingException {
-        String msg = "Illegal statement decriptor: Reason SORT. Expected ASC or DSC";
-        if (currTokenIndex >= tokens.length) {
-            throw new DescriptorParsingException(msg);
-        }
-        if (tokens[currTokenIndex].equals(KEYWORD_ASC)) {
-            member.setDirection(SortDirection.ASCENDING);
-            currTokenIndex++;
-        } else if (tokens[currTokenIndex].equals(KEYWORD_DSC)) {
-            member.setDirection(SortDirection.DESCENDING);
-            currTokenIndex++;
-        } else {
-            throw new DescriptorParsingException(msg);
-        }
-    }
-
-    private void matchWhereExp(Node node) throws DescriptorParsingException {
-        if (currTokenIndex >= tokens.length) {
-            throw new DescriptorParsingException("Illegal where clause");
-        }
-        assert(node != null);
-        matchAndCondition(node);
-        matchOrCondition(node);
-    }
-
-    private void matchAndCondition(Node currNode) throws DescriptorParsingException {
-        matchCondition(currNode);
-        matchAndExpression(currNode);
-    }
-
-    private void matchCondition(Node currNode) throws DescriptorParsingException {
-        if (currTokenIndex >= tokens.length) {
-            throw new DescriptorParsingException("Illegal statement descriptor: Reason sort clause");
-        }
-        if (tokens[currTokenIndex].equals(Operator.NOT.getName())) {
-            NotBooleanExpressionNode notNode = new NotBooleanExpressionNode(currNode);
-            if (currNode instanceof BinaryExpressionNode) {
-                BinaryExpressionNode currNodeExpr = (BinaryExpressionNode)currNode;
-                Node available = currNodeExpr.getLeftChild();
-                if (available != null) {
-                    currNodeExpr.setRightChild(notNode);
-                } else {
-                    currNodeExpr.setLeftChild(notNode);
-                }
-            } else {
-                assert(currNode instanceof NotBooleanExpressionNode || currNode instanceof Node);
-                currNode.setValue(notNode);
-            }
-            currTokenIndex++; // NOT keyword
-            
-            matchCondition(notNode);
-        } else {
-            matchComparisionExpression(currNode);
-        }
-    }
-
-    private void matchComparisionExpression(Node currNode) throws DescriptorParsingException {
-        if (currTokenIndex >= tokens.length) {
-            throw new DescriptorParsingException("Illegal statement descriptor: Comparison expression");
-        }
-        BinaryExpressionNode expr = new BinaryExpressionNode(currNode);
-        TerminalNode left = new TerminalNode(expr);
-        TerminalNode right = new TerminalNode(expr);
-        expr.setLeftChild(left);
-        expr.setRightChild(right);
-        
-        if (currNode instanceof BinaryExpressionNode) {
-            BinaryExpressionNode currNodeExpr = (BinaryExpressionNode)currNode;
-            Node available = currNodeExpr.getLeftChild();
-            if (available == null) {
-                currNodeExpr.setLeftChild(expr);
-            } else {
-                assert(currNodeExpr.getRightChild() == null);
-                currNodeExpr.setRightChild(expr);
-            }
-        } else {
-            assert(currNode instanceof NotBooleanExpressionNode || currNode instanceof Node);
-            currNode.setValue(expr);
-        }
-        
-        matchTerm(left, true);
-        matchComparisonRHS(expr);
-    }
-
-    private void matchComparisonRHS(BinaryExpressionNode currNode) throws DescriptorParsingException {
-        if (currTokenIndex >= tokens.length) {
-            // boolean literals are not allowed
-            throw new DescriptorParsingException("Illegal statement descriptor: Boolean literals are not allowed!");
-        }
-        if (tokens[currTokenIndex].equals(Operator.EQUALS.getName())) {
-            currTokenIndex++;
-            currNode.setOperator(BinaryComparisonOperator.EQUALS);
-            matchTerm((TerminalNode)currNode.getRightChild(), false);
-        } else if (tokens[currTokenIndex].equals(Operator.LESS_THAN_OR_EQUAL_TO.getName())) {
-            currTokenIndex++;
-            currNode.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-            matchTerm((TerminalNode)currNode.getRightChild(), false);
-        } else if (tokens[currTokenIndex].equals(Operator.GREATER_THAN_OR_EQUAL_TO.getName())) {
-            currTokenIndex++;
-            currNode.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-            matchTerm((TerminalNode)currNode.getRightChild(), false);
-        } else if (tokens[currTokenIndex].equals(Operator.GREATER_THAN.getName())) {
-            currTokenIndex++;
-            currNode.setOperator(BinaryComparisonOperator.GREATER_THAN);
-            matchTerm((TerminalNode)currNode.getRightChild(), false);
-        } else if (tokens[currTokenIndex].equals(Operator.LESS_THAN.getName())) {
-            currTokenIndex++;
-            currNode.setOperator(BinaryComparisonOperator.LESS_THAN);
-            matchTerm((TerminalNode)currNode.getRightChild(), false);
-        } else if (tokens[currTokenIndex].equals(Operator.NOT_EQUAL_TO.getName())) {
-            currTokenIndex++;
-            currNode.setOperator(BinaryComparisonOperator.NOT_EQUAL_TO);
-            matchTerm((TerminalNode)currNode.getRightChild(), false);
-        } else {
-            throw new DescriptorParsingException("Illegal statement descriptor: Reason comparison expression!");
-        }
-    }
-    
-    private void matchTerm(SortMember member) throws DescriptorParsingException {
-        String term = getTerm();
-        if (term.charAt(0) == PARAM_PLACEHOLDER) {
-            assert(placeHolderCount > 0);
-            ensureValidType(term, "SORT");
-            if (term.charAt(1) != 's') {
-                String msg = "Sort parameters only accept string types. Placeholder was: " + term;
-                throw new DescriptorParsingException(msg);
-            }
-            UnfinishedSortKey unfinishedKey = new UnfinishedSortKey();
-            unfinishedKey.setParameterIndex(placeHolderCount - 1);
-            member.setSortKey(unfinishedKey);
-            return;
-        }
-        String stringTerm = getStringTerm(term);
-        member.setSortKey(stringTerm);
-    }
-    
-    /*
-     * Check if the free parameter type is valid in a given context. Currently,
-     * list and pojo free type parameters are invalid for LIMIT, SORT and WHERE.
-     *  
-     * Currently, no list types and no Pojo types are allowed.
-     */
-    private void ensureValidType(String term, String contextName) throws DescriptorParsingException {
-        if (term.length() > 2) {
-            // Don't allow list types for invalid contexts
-            // Only list type free variables have 3 characters
-            String format = "List free variable type not allowed in %s context";
-            String msg = String.format(format, contextName);
-            throw new DescriptorParsingException(msg);
-        }
-        if (term.equals(POJO_FREE_PARAMETER_TYPE)) {
-            String format = "Pojo free variable type not allowed in %s context";
-            String msg = String.format(format, contextName);
-            throw new DescriptorParsingException(msg);
-        }
-    }
-    
-    private void matchTerm(LimitExpression expn) throws DescriptorParsingException {
-        String term = getTerm();
-        if (term.charAt(0) == PARAM_PLACEHOLDER) {
-            assert(placeHolderCount > 0);
-            ensureValidType(term, "LIMIT");
-            if (term.charAt(1) != 'i') {
-                String msg = "Limit parameters only accept integer types. Placeholder was: " + term;
-                throw new DescriptorParsingException(msg);
-            }
-            UnfinishedLimitValue limitValue = new UnfinishedLimitValue();
-            limitValue.setParameterIndex(placeHolderCount - 1);
-            expn.setValue(limitValue);
-            return;
-        }
-        int limitVal;
-        try {
-            limitVal = Integer.parseInt(term);
-        } catch (NumberFormatException e) {
-            throw new DescriptorParsingException("Invalid limit expression. '" + term + "' not an integer");
-        }
-        expn.setValue(limitVal);
-    }
-    
-    /**
-     * Calls {@link #matchTerm(TerminalNode, boolean, boolean)} with a
-     * {@code false isSetListContext} parameter.
-     */
-    private void matchTerm(TerminalNode node, boolean isLHS) throws DescriptorParsingException {
-        // default to false
-        matchTerm(node, isLHS, false);
-    }
-
-    /**
-     * Match a terminal in a TerminalNode context. Only where expression, and
-     * set list context take this code path.
-     * 
-     * @param node
-     *            The terminal node which is parsed at this point.
-     * @param isLHS
-     *            {@code true} if and only if the node is the left hand side of
-     *            a binary expression.
-     * @param isSetListContext
-     *            {@code true} if and only if the node is in a set list context
-     *            or conversely NOT in a where expression context.
-     * @throws DescriptorParsingException
-     *             If and error was encountered parsing the terminal string
-     *             token.
-     */
-    private void matchTerm(TerminalNode node, boolean isLHS,
-            boolean isSetListContext) throws DescriptorParsingException {
-        String term = getTerm();
-        if (term.charAt(0) == PARAM_PLACEHOLDER) {
-            assert(placeHolderCount > 0);
-            if (!isSetListContext) {
-                ensureValidType(term, "WHERE");
-            }
-            UnfinishedValueNode patchNode = new UnfinishedValueNode();
-            patchNode.setParameterIndex(placeHolderCount - 1);
-            patchNode.setLHS(isLHS);
-            // figure out the expected type
-            Class<?> expectedType = getType(term.substring(1));
-            if (expectedType == null) {
-                throw new DescriptorParsingException("Unknown type of free parameter: '" + term + "'");
-            }
-            patchNode.setType(expectedType);
-            node.setValue(patchNode);
-            return;
-        }
-        // regular terminal. i.e. literal value
-        if (isLHS) {
-            // FIXME: In thermostat LHS of comparisons must be Key objects. I'm
-            // not sure if this restriction is very meaningful in a prepared
-            // statement context as the purpose of this was to ensure "type"
-            // compatibility between Key <=> value comparisons.
-            String stringTerm = getStringTerm(term);
-            Key<?> key = new Key<>(stringTerm);
-            node.setValue(key);
-        } else {
-            Object typedValue = getTypedValue(term);
-            node.setValue(typedValue);
-        }
-    }
-    
-    private Object getTypedValue(String term) throws DescriptorParsingException {
-        try {
-            String stringTerm = getStringTerm(term);
-            return stringTerm;
-        } catch (DescriptorParsingException e) {
-            // Must be integer (long/int) or boolean. First check for boolean,
-            // then for long and regular ints.
-            if (term.equals(Boolean.toString(false)) || term.equals(Boolean.toString(true))) {
-                boolean boolVal = Boolean.parseBoolean(term);
-                return boolVal;
-            }
-            // Next, parse long or int.
-            try {
-                int lastCharInTokenIndex = term.length() - 1;
-                // preceding l/L indicate long integer types.
-                if (term.charAt(lastCharInTokenIndex) == 'L' || term.charAt(lastCharInTokenIndex) == 'l') {
-                    long longVal = Long.parseLong(term.substring(0, lastCharInTokenIndex));
-                    return longVal;
-                }
-                // must be integer or some invalid type
-                int intVal = Integer.parseInt(term);
-                return intVal;
-            } catch (NumberFormatException nfe) {
-                String msg = "Illegal terminal type. Token was ->" + term + "<-";
-                throw new DescriptorParsingException(msg);
-            }
-        }
-    }
-
-    private String getStringTerm(String term) throws DescriptorParsingException {
-        String errorMsg = 
-                "Expected string value. Got term ->"
-                        + term
-                        + "<-"
-                        + " Was the string properly quoted? Example: 'string'.";
-        if (term.charAt(0) != '\'' || term.charAt(term.length() - 1) != '\'') {
-            throw new DescriptorParsingException(errorMsg);
-        }
-        return term.substring(1, term.length() - 1);
-    }
-
-    private Class<?> getType(String term) {
-        if (term.equals("")) {
-            // illegal type
-            return null;
-        }
-        // free variable types can have 1 or 2 characters.
-        assert(term.length() > 0 && term.length() < 3);
-        char switchChar = term.charAt(0);
-        Class<?> typeToken = null;
-        switch (switchChar) {
-        case 'i': {
-            if (term.length() == 1) {
-                typeToken = int.class;
-            } else if (term.length() == 2 && term.charAt(1) == '[') {
-                typeToken = int[].class;
-            }
-            break;
-        }
-        case 'l': {
-            if (term.length() == 1) {
-                typeToken = long.class;
-            } else if (term.length() == 2 && term.charAt(1) == '[') {
-                typeToken = long[].class;
-            }
-            break;
-        }
-        case 's': {
-            if (term.length() == 1) {
-                typeToken = String.class;
-            } else if (term.length() == 2 && term.charAt(1) == '[') {
-                typeToken = String[].class;
-            }
-            break;
-        }
-        case 'b': {
-            if (term.length() == 1) {
-                typeToken = boolean.class;
-            } else if (term.length() == 2 && term.charAt(1) == '[') {
-                typeToken = boolean[].class;
-            }
-            break;
-        }
-        case 'd': {
-            if (term.length() == 1) {
-                typeToken = double.class;
-            } else if (term.length() == 2 && term.charAt(1) == '[') {
-                typeToken = double[].class;
-            }
-            break;
-        }
-        case 'p': {
-            if (term.length() == 1) {
-                typeToken = Pojo.class;
-            } else if (term.length() == 2 && term.charAt(1) == '[') {
-                typeToken = Pojo[].class;
-            }
-            break;
-        }
-        default:
-            assert(typeToken == null);
-            break;
-        }
-        return typeToken;
-    }
-
-    private String getTerm() throws DescriptorParsingException {
-        if (currTokenIndex >= tokens.length) {
-            throw new DescriptorParsingException("Invalid where clause. Reason: term expected but not given!");
-        }
-        if (tokens[currTokenIndex].charAt(0) == PARAM_PLACEHOLDER) {
-                placeHolderCount++;
-        }
-        String term = tokens[currTokenIndex];
-        currTokenIndex++;
-        return term;
-    }
-
-    private void matchAndExpression(Node currNode) throws DescriptorParsingException {
-        if (currTokenIndex < tokens.length &&
-                tokens[currTokenIndex].equals(Operator.AND.getName())) {
-            currTokenIndex++; // AND keyword
-            
-            Node parent = currNode;
-            if (currNode instanceof BinaryExpressionNode ||
-                    currNode instanceof NotBooleanExpressionNode) {
-                parent = currNode.getParent();
-                assert(parent != null);
-            }
-            BinaryExpressionNode and = new BinaryExpressionNode(parent);
-            and.setOperator(BinaryLogicalOperator.AND);
-            if (currNode instanceof BinaryExpressionNode ||
-                    currNode instanceof NotBooleanExpressionNode) {
-                currNode.setParent(and);
-                and.setLeftChild(currNode);
-                parent.setValue(and);
-            } else {
-                // Root node case
-                and.setLeftChild((Node)parent.getValue());
-                parent.setValue(and);
-            }
-            // Note the current AND expression node at this point of parsing
-            // must be at the root of the entire expression.
-            assert(and.getParent().getParent() == null);
-            
-            matchWhereExp(and);
-            
-        }
-        // empty
-    }
-
-    private void matchOrCondition(Node currNode) throws DescriptorParsingException {
-        if (currTokenIndex < tokens.length &&
-                tokens[currTokenIndex].equals(Operator.OR.getName())) {
-            currTokenIndex++; // OR keyword
-            
-            Node parent = currNode;
-            if (currNode instanceof BinaryExpressionNode ||
-                    currNode instanceof NotBooleanExpressionNode) {
-                parent = currNode.getParent();
-                assert(parent != null);
-            }
-            BinaryExpressionNode or = new BinaryExpressionNode(parent);
-            or.setOperator(BinaryLogicalOperator.OR);
-            if (currNode instanceof BinaryExpressionNode ||
-                    currNode instanceof NotBooleanExpressionNode) {
-                currNode.setParent(or);
-                or.setLeftChild(currNode);
-                parent.setValue(or);
-            } else {
-                // Root node case
-                or.setLeftChild((Node)parent.getValue());
-                parent.setValue(or);
-            }
-            // Note the current OR expression node at this point of parsing
-            // must be at the root of the entire expression.
-            assert(or.getParent().getParent() == null);
-            
-            matchWhereExp(or);
-        }
-        // empty
-    }
-
-    private void createStatement() {
-        // matchStatementType and matchCategory advanced currTokenIndex,
-        // lets use idx of 0 here.
-        final String statementType = tokens[0];
-        Matcher queryCountMatcher = QUERY_COUNT_PATTERN.matcher(statementType);
-        Matcher queryDistinctMatcher = QUERY_DISTINCT_PATTERN.matcher(statementType);
-        if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_QUERY])) {
-            // regular query case
-            Query<T> query = storage.createQuery(desc.getCategory());
-            this.parsedStatement = new ParsedStatementImpl<>(query);
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_ADD])) {
-            // create add
-            Add<T> add = storage.createAdd(desc.getCategory());
-            this.parsedStatement = new ParsedStatementImpl<>(add);
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_REPLACE])) {
-            // create replace
-            Replace<T> replace = storage.createReplace(desc.getCategory());
-            this.parsedStatement = new ParsedStatementImpl<>(replace);
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_UPDATE])) {
-            // create replace
-            Update<T> update = storage.createUpdate(desc.getCategory());
-            this.parsedStatement = new ParsedStatementImpl<>(update);
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_REMOVE])) {
-            // create remove
-            Remove<T> remove = storage.createRemove(desc.getCategory());
-            this.parsedStatement = new ParsedStatementImpl<>(remove);
-        } else if (queryCountMatcher.matches()) {
-            this.parsedStatement = createAggregatePreparedStatement(AggregateFunction.COUNT, queryCountMatcher);
-        } else if (queryDistinctMatcher.matches()) {
-            this.parsedStatement = createAggregatePreparedStatement(AggregateFunction.DISTINCT, queryDistinctMatcher);
-        } else {
-            throw new IllegalStateException("Don't know how to create statement type '" + statementType + "'");
-        }
-    }
-    
-    private ParsedStatementImpl<T> createAggregatePreparedStatement(final AggregateFunction function, final Matcher matcher) {
-        // create aggregate query
-        AggregateQuery<T> aggregateQuery = storage.createAggregateQuery(function, desc.getCategory());
-        // We'll always have a match for at least one group. That group
-        // will be the keyName to use (if any). For old query descriptors
-        // the keyName may be null
-        String keyName = matcher.group(1); // groups start at 1
-        if (keyName != null) {
-            Key<?> aggKey = new Key<>(keyName);
-            aggregateQuery.setAggregateKey(aggKey);
-        }
-        return new ParsedStatementImpl<>(aggregateQuery);
-    }
-
-    private void matchCategory() throws DescriptorParsingException {
-        if (currTokenIndex >= tokens.length) {
-            throw new DescriptorParsingException("Missing category name in descriptor: '" + desc.getDescriptor() + "'");
-        }
-        Category<?> category = desc.getCategory();
-        if (!tokens[currTokenIndex].equals(category.getName())) {
-            throw new DescriptorParsingException(
-                    "Category mismatch in descriptor. Category from descriptor string: '"
-                            + tokens[currTokenIndex]
-                            + "'. Category name from category: '"
-                            + category.getName() + "'.");
-        }
-        currTokenIndex++;
-    }
-
-    private void matchStatementType() throws DescriptorParsingException {
-        final String statementType = tokens[currTokenIndex];
-        Matcher queryCountMatcher = QUERY_COUNT_PATTERN.matcher(statementType);
-        Matcher queryDistinctMatcher = QUERY_DISTINCT_PATTERN.matcher(statementType);
-        if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_QUERY])) {
-            // QUERY
-            currTokenIndex++;
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_ADD])) {
-            // ADD
-            currTokenIndex++;
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_REPLACE])) {
-            // REPLACE
-            currTokenIndex++;
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_UPDATE])) {
-            // UPDATE
-            currTokenIndex++;
-        } else if (statementType.equals(KNOWN_STATEMENT_TYPES[IDX_REMOVE])) {
-            // REMOVE
-            currTokenIndex++;
-        } else if (queryCountMatcher.matches()) {
-            // QUERY-COUNT
-            currTokenIndex++;
-        } else if (queryDistinctMatcher.matches()) {
-            // QUERY-DISTINCT
-            currTokenIndex++;
-        } else {
-            throw new DescriptorParsingException("Unknown statement type: '" + statementType + "'");
-        }
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/BinaryExpressionNode.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.query.BinaryComparisonExpression;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.LiteralExpression;
-import com.redhat.thermostat.storage.query.Operator;
-
-class BinaryExpressionNode extends Node {
-    
-    private Node leftChild;
-    private Node rightChild;
-    private Operator operator;
-
-    public Operator getOperator() {
-        return operator;
-    }
-
-    public void setOperator(Operator operator) {
-        this.operator = operator;
-    }
-
-    BinaryExpressionNode(Node parent) {
-        super(parent);
-    }
-
-    public Node getLeftChild() {
-        return leftChild;
-    }
-
-    public void setLeftChild(Node leftChild) {
-        this.leftChild = leftChild;
-    }
-
-    public Node getRightChild() {
-        return rightChild;
-    }
-
-    public void setRightChild(Node rightChild) {
-        this.rightChild = rightChild;
-    }
-    
-    @Override
-    public PatchedWhereExpression patch(PreparedParameter[] params) throws IllegalPatchException {
-        if (leftChild == null || rightChild == null || getOperator() == null) {
-            String msg = BinaryExpressionNode.class.getSimpleName() +
-                    " invalid when attempted to patch";
-            IllegalStateException cause = new IllegalStateException(msg);
-            throw new IllegalPatchException(cause);
-        }
-        PatchedWhereExpression left = leftChild.patch(params);
-        PatchedWhereExpression right = rightChild.patch(params);
-        
-        Expression leftExpression = left.getExpression();
-        Expression rightExpression = right.getExpression();
-        return createExpression(leftExpression, rightExpression);
-    }
-
-    private PatchedWhereExpression createExpression(Expression leftExpression,
-            Expression rightExpression) {
-        if (operator instanceof BinaryComparisonOperator) {
-            return getBinaryComparisonExpression(leftExpression, (BinaryComparisonOperator) operator, rightExpression);
-        } else if (operator instanceof BinaryLogicalOperator) {
-            return getBinaryLogicalExpression(leftExpression, (BinaryLogicalOperator) operator, rightExpression);
-        }
-        return null;
-    }
-    
-    private PatchedWhereExpression getBinaryLogicalExpression(Expression a,
-            BinaryLogicalOperator op, Expression b) {
-        BinaryLogicalExpression<Expression, Expression> impl = new BinaryLogicalExpression<Expression, Expression>(
-                a, op, b);
-        return new PatchedWhereExpressionImpl(impl);
-    }
-
-    @SuppressWarnings("unchecked") // Unchecked casts to LiteralExpression
-    private <T> PatchedWhereExpressionImpl getBinaryComparisonExpression(Expression a, BinaryComparisonOperator op, Expression b) {
-        LiteralExpression<Key<T>> leftOperand = (LiteralExpression<Key<T>>) a;
-        LiteralExpression<T> rightOperand = (LiteralExpression<T>)b;
-        BinaryComparisonExpression<T> impl = new BinaryComparisonExpression<>(
-                leftOperand, op, rightOperand);
-        return new PatchedWhereExpressionImpl(impl);
-    }
-
-    @Override
-    public void print(int level) {
-        for (int i = 0; i < level; i++) {
-            System.out.print("-");
-        }
-        System.out.print("B: " + getOperator());
-        System.out.println("");
-        int newLevel = level + 1;
-        if (leftChild != null) {
-            leftChild.print(newLevel);
-        }
-        if (rightChild != null) {
-            rightChild.print(newLevel);
-        }
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        if (other == null) {
-            return false;
-        }
-        if (!(other instanceof BinaryExpressionNode)) {
-            return false;
-        }
-        BinaryExpressionNode o = (BinaryExpressionNode)other;
-        return this.getOperator().equals(o.getOperator()) &&
-                Objects.equals(leftChild, o.leftChild) &&
-                Objects.equals(rightChild, o.rightChild);
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(getOperator(), leftChild, rightChild, getParent());
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/LimitExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-/**
- * Represents a limit expression in the prepared statement's parse tree.
- *
- */
-class LimitExpression implements Printable, Patchable {
-
-    private Object value;
-
-    public Object getValue() {
-        return value;
-    }
-
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    @Override
-    public void print(int level) {
-        System.out.println("LIMIT: " + getValue());
-    }
-
-    @Override
-    public PatchedLimitExpression patch(PreparedParameter[] params)
-            throws IllegalPatchException {
-        if (value instanceof Unfinished) {
-            Unfinished unfinished = (Unfinished)value;
-            try {
-                PreparedParameter param = params[unfinished.getParameterIndex()];
-                Class<?> typeClass = param.getType();
-                if (typeClass != int.class) {
-                    String msg = "Invalid parameter type for limit expression. Expected integer!";
-                    IllegalArgumentException e = new IllegalArgumentException(msg);
-                    throw e;
-                }
-                int limitVal = (Integer)param.getValue();
-                return new PatchedLimitExpressionImpl(limitVal);
-            } catch (Exception e) {
-                throw new IllegalPatchException(e);
-            }
-        } else {
-            // must have been int, since parsing would have failed otherwise
-            int limitVal = (int)getValue();
-            return new PatchedLimitExpressionImpl(limitVal);
-        }
-    }
-    
-    private static class PatchedLimitExpressionImpl implements PatchedLimitExpression {
-        
-        private final int val;
-        
-        PatchedLimitExpressionImpl(int limitVal) {
-            this.val = limitVal;
-        }
-
-        @Override
-        public int getLimitValue() {
-            return val;
-        }
-        
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Node.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-/**
- * A basic node in the prepared statement parse tree.
- *
- */
-class Node implements Printable, Patchable {
-
-    private Node parent;
-
-    private Object value;
-    
-    Node(Node parent) {
-        this.parent = parent;
-    }
-    
-    public Object getValue() {
-        return value;
-    }
-
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    public Node getParent() {
-        return parent;
-    }
-
-    public void setParent(Node parent) {
-        this.parent = parent;
-    }
-
-    @Override
-    public void print(int level) {
-        for (int i = 0; i < level; i++) {
-            System.out.print("-");
-        }
-        System.out.print(getValue());
-        System.out.println("");
-        if (value instanceof Node) {
-            Node node = (Node)value;
-            node.print(level + 1);
-        }
-    }
-    
-    @Override
-    public PatchedWhereExpression patch(PreparedParameter[] params) throws IllegalPatchException {
-        if (getValue() == null || !(getValue() instanceof Node) ) {
-            String msg = Node.class.getSimpleName() +
-                    " invalid when attempted to patch";
-            IllegalStateException cause = new IllegalStateException(msg);
-            throw new IllegalPatchException(cause);
-        }
-        Node node = (Node)getValue();
-        return node.patch(params);
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (other == null) {
-            return false;
-        }
-        if (!(other instanceof Node)) {
-            return false;
-        }
-        Node o = (Node)other;
-        return Objects.equals(getValue(), o.getValue());
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(getValue());
-    }
-    
-    @Override
-    public String toString() {
-        return "Node: " + getValue();
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/NotBooleanExpressionNode.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.query.ComparisonExpression;
-import com.redhat.thermostat.storage.query.UnaryLogicalExpression;
-import com.redhat.thermostat.storage.query.UnaryLogicalOperator;
-
-/**
- * A node representing a boolean not expression in the prepared statement's
- * parse tree.
- *
- */
-class NotBooleanExpressionNode extends UnaryExpressionNode {
-
-    NotBooleanExpressionNode(Node parent) {
-        super(parent);
-    }
-
-    @Override
-    public UnaryLogicalOperator getOperator() {
-        return UnaryLogicalOperator.NOT;
-    }
-    
-    @Override
-    public PatchedWhereExpression patch(PreparedParameter[] params) throws IllegalPatchException {
-        if (getValue() == null || !(getValue() instanceof Node) ) {
-            String msg = getClass().getSimpleName() +
-                    " invalid when attempted to patch";
-            IllegalStateException cause = new IllegalStateException(msg);
-            throw new IllegalPatchException(cause);
-        }
-        Node node = (Node)getValue();
-        PatchedWhereExpression patched = node.patch(params);
-        // If this cast fails we are in serious trouble. Mongodb doesn't support
-        // something like NOT ( a AND b ). However, the grammar does not support
-        // parenthesized expressions, NOT has higher precedence as AND/OR
-        // expressions and the LHS and RHS of binary boolean expressions are
-        // required to be binary comparison expressions.
-        // Hence, we wouldn't parse an expression such as the above anyway.
-        ComparisonExpression expr = (ComparisonExpression)patched.getExpression();
-        UnaryLogicalExpression<ComparisonExpression> notExpr = new UnaryLogicalExpression<>(
-                expr, getOperator());
-        return new PatchedWhereExpressionImpl(notExpr);
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        if (other == null) {
-            return false;
-        }
-        if (!(other instanceof NotBooleanExpressionNode)) {
-            return false;
-        }
-        NotBooleanExpressionNode o = (NotBooleanExpressionNode)other;
-        return Objects.equals(getValue(), o.getValue());
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(getOperator(), getValue());
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Operator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/**
- * Valid operators in the string representation of a prepared statement
- * descriptor.
- *
- */
-enum Operator {
-    
-    /** Logical AND operation */
-    AND("AND"),
-    /** Logical OR operation */
-    OR("OR"),
-    /** Logical NOT operation */
-    NOT("NOT"),
-    /** Equality comparison */
-    EQUALS("="),
-    /** Inequality comparison */
-    NOT_EQUAL_TO("!="),
-    /** Greater than comparison */
-    GREATER_THAN(">"),
-    /** Greater than or equal comparison */
-    GREATER_THAN_OR_EQUAL_TO(">="),
-    /** Less than comparison */
-    LESS_THAN("<"),
-    /** Less than or equal comparison */
-    LESS_THAN_OR_EQUAL_TO("<=");
-    
-    private String name;
-    
-    Operator(String name) {
-        this.name = name;
-    }
-    
-    public String getName() {
-        return name;
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImpl.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-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.Statement;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Result object as returned by {@link BasicDescriptorParser#parse()}.
- * An instance of this plus a list of {@link PreparedParameter} should
- * be sufficient to patch up a prepared statement with its real values.
- *
- * @see PreparedStatementImpl#executeQuery()
- */
-class ParsedStatementImpl<T extends Pojo> implements ParsedStatement<T> {
-
-    private final Statement<T> statement;
-    private int numParams;
-    private SuffixExpression suffixExpn;
-    private SetList setList;
-
-    ParsedStatementImpl(Statement<T> statement) {
-        this.statement = statement;
-    }
-    
-    @Override
-    public int getNumParams() {
-        return numParams;
-    }
-
-    @Override
-    public Statement<T> patchStatement(PreparedParameter[] params) throws IllegalPatchException {
-        if (suffixExpn == null) {
-            String msg = "Suffix expression must be set before patching!";
-            IllegalStateException expn = new IllegalStateException(msg);
-            throw new IllegalPatchException(expn);
-        }
-        
-        /*
-         * Statements may not be stateless and hence, we need to create a
-         * duplicate prior every patch + execution.
-         */
-        Statement<T> stmt = statement.getRawDuplicate();
-        
-        patchSetList(stmt, params);
-        patchWhere(stmt, params);
-        patchSort(stmt, params);
-        patchLimit(stmt, params);
-        // TODO count actual patches and throw an exception if not all vars
-        // have been patched up.
-        return stmt;
-    }
-
-    private void patchSetList(Statement<T> stmt, PreparedParameter[] params) throws IllegalPatchException {
-        if (setList.getValues().size() == 0) {
-            // no set list, nothing to do
-            return;
-        }
-        // do the patching
-        PatchedSetList patchedSetList = setList.patch(params);
-        // set the values
-        if (stmt instanceof Add) {
-            Add<T> add = (Add<T>)stmt;
-            for (PatchedSetListMember member: patchedSetList.getSetListMembers()) {
-                add.set(member.getKey().getName(), member.getValue());
-            }
-        }
-        if (stmt instanceof Replace) {
-            Replace<T> replace = (Replace<T>)stmt;
-            for (PatchedSetListMember member: patchedSetList.getSetListMembers()) {
-                replace.set(member.getKey().getName(), member.getValue());
-            }
-        }
-        if (stmt instanceof Update) {
-            Update<T> update = (Update<T>)stmt;
-            for (PatchedSetListMember member: patchedSetList.getSetListMembers()) {
-                update.set(member.getKey().getName(), member.getValue());
-            }
-        }
-    }
-
-    private void patchLimit(Statement<T> stmt, PreparedParameter[] params) throws IllegalPatchException {
-        LimitExpression expn = suffixExpn.getLimitExpn();
-        if (expn == null) {
-            // no limit expn, nothing to do
-            return;
-        }
-        PatchedLimitExpression patchedExp = expn.patch(params);
-        if (stmt instanceof Query) {
-            Query<T> query = (Query<T>) stmt;
-            query.limit(patchedExp.getLimitValue());
-        } else {
-            String msg = "Patching 'limit' of non-query types not supported! Class was:"
-                    + stmt.getClass().getName();
-            IllegalStateException invalid = new IllegalStateException(msg);
-            throw new IllegalPatchException(invalid);
-        }
-    }
-
-    private void patchSort(Statement<T> stmt, PreparedParameter[] params) throws IllegalPatchException {
-        SortExpression expn = suffixExpn.getSortExpn();
-        if (expn == null) {
-            // no sort expn, nothing to do
-            return;
-        }
-        PatchedSortExpression patchedExp = expn.patch(params);
-        if (stmt instanceof Query) {
-            Query<T> query = (Query<T>) stmt;
-            PatchedSortMember[] members = patchedExp.getSortMembers();
-            for (int i = 0; i < members.length; i++) {
-                query.sort(members[i].getSortKey(), members[i].getDirection());
-            }
-        } else {
-            String msg = "Patching 'sort' of non-query types not supported! Class was:"
-                    + stmt.getClass().getName();
-            IllegalStateException invalid = new IllegalStateException(msg);
-            throw new IllegalPatchException(invalid);
-        }
-    }
-
-    private void patchWhere(Statement<T> stmt, PreparedParameter[] params) throws IllegalPatchException {
-        WhereExpression expn = suffixExpn.getWhereExpn();
-        if (expn == null) {
-            // no where, nothing to do
-            return;
-        }
-        // walk the tree, create actual expressions and patch values along
-        // the way.
-        PatchedWhereExpression patchedExp = expn.patch(params);
-        Expression whereClause = patchedExp.getExpression();
-        if (stmt instanceof Query) {
-            Query<T> query = (Query<T>) stmt;
-            query.where(whereClause);
-        } else if (stmt instanceof Replace) {
-            Replace<T> replace = (Replace<T>) stmt;
-            replace.where(whereClause);
-        } else if (stmt instanceof Update) {
-            Update<T> update = (Update<T>) stmt;
-            update.where(whereClause);
-        } else if (stmt instanceof Remove) {
-            Remove<T> remove = (Remove<T>) stmt;
-            remove.where(whereClause);
-        } else {
-            String msg = "Patching of where clause not supported! Class was:"
-                    + stmt.getClass().getName();
-            IllegalStateException invalid = new IllegalStateException(msg);
-            throw new IllegalPatchException(invalid);
-        }
-    }
-    
-    Statement<T> getRawStatement() {
-        return statement;
-    }
-
-    void setNumFreeParams(int num) {
-        this.numParams = num;
-    }
-
-    void setSuffixExpression(SuffixExpression tree) {
-        this.suffixExpn = tree;
-    }
-
-    SuffixExpression getSuffixExpression() {
-        return suffixExpn;
-    }
-
-    SetList getSetList() {
-        return setList;
-    }
-
-    void setSetList(SetList setList) {
-        this.setList = setList;
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Patchable.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-/**
- * Interface for patchable objects in a ParsedStatement.
- *
- */
-interface Patchable {
-    
-    /**
-     * 
-     * @param params The parameters which should be used for patching.
-     * @return The finished (a.k.a patched) expression.
-     * @throws IllegalPatchException If something failed during patching.
-     */
-    PatchedExpression patch(PreparedParameter[] params) throws IllegalPatchException;
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
-import com.redhat.thermostat.storage.core.Key;
-
-/**
- * Return type for patched expressions
- * 
- * @see Patchable
- */
-interface PatchedExpression {
-    // marker interface
-}
-
-interface PatchedWhereExpression extends PatchedExpression {
-    
-    /**
-     * @return The patched where expression.
-     * 
-     * @see {@link Expression}
-     */
-    Expression getExpression();
-}
-
-interface PatchedSortExpression extends PatchedExpression {
-    
-    /**
-     * 
-     * @return The patched sorts.
-     * 
-     * @see {@link PatchedSortMember}
-     * @see {@link Query#sort(Key, SortDirection)}
-     */
-    PatchedSortMember[] getSortMembers();
-    
-}
-
-interface PatchedSortMemberExpression extends PatchedExpression {
-    
-    /**
-     * 
-     * @return The patched sorts.
-     * 
-     * @see {@link PatchedSortMember}
-     * @see {@link Query#sort(Key, SortDirection)}
-     */
-    PatchedSortMember getSortMember();
-    
-}
-
-interface PatchedLimitExpression extends PatchedExpression {
-    
-    /**
-     * 
-     * @return The patched limit value.
-     * 
-     * @see {@link Query#limit(int)}
-     */
-    int getLimitValue();
-    
-}
-
-interface PatchedSetListMemberExpression extends PatchedExpression {
-    
-    /**
-     * 
-     * @return The patched set list member.
-     */
-    PatchedSetListMember getSetListMember();
-}
-
-interface PatchedSetList extends PatchedExpression {
-    
-    /**
-     * @return The patched set list
-     * 
-     */
-    PatchedSetListMember[] getSetListMembers();
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedSetListMember.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.Key;
-
-/**
- * Data structure representing patched SET lists members.
- *
- */
-class PatchedSetListMember {
-
-    private final Key<?> key;
-    private final Object value;
-    
-    PatchedSetListMember(Key<?> key, Object value) {
-        this.key = key;
-        this.value = value;
-    }
-
-    Key<?> getKey() {
-        return key;
-    }
-
-    Object getValue() {
-        return value;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedSortMember.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
-
-/**
- * Data structure representing patched sort members.
- *
- * @see Patchable
- * @see PatchedSortExpression
- * @see SortMember
- */
-class PatchedSortMember {
-
-    private final SortDirection direction;
-    private final Key<?> sortKey;
-
-    PatchedSortMember(Key<?> sortKey, SortDirection direction) {
-        this.direction = direction;
-        this.sortKey = sortKey;
-    }
-    
-    SortDirection getDirection() {
-        return direction;
-    }
-
-    Key<?> getSortKey() {
-        return sortKey;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PatchedWhereExpressionImpl.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * Implementation of the return type of patchable where expressions.
- *
- */
-class PatchedWhereExpressionImpl implements PatchedWhereExpression {
-    
-    private final Expression expn;
-    
-    PatchedWhereExpressionImpl(Expression expn) {
-        this.expn = expn;
-    }
-
-    @Override
-    public Expression getExpression() {
-        return expn;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright 2012-2017 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.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;
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.PreparedParameters;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Query;
-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.model.Pojo;
-
-/**
- * Main implementation of {@link PreparedStatement}s.
- *
- */
-final public class PreparedStatementImpl<T extends Pojo> implements PreparedStatement<T> {
-    
-    private StatementDescriptor<T> desc;
-    private Query<T> query;
-    private DataModifyingStatement<T> dmlStatement;
-    private final PreparedParameters params;
-    private final ParsedStatementImpl<T> parsedStatement;
-    
-    public PreparedStatementImpl(BackingStorage storage, StatementDescriptor<T> desc) throws DescriptorParsingException {
-        this.desc = desc;
-        StatementDescriptorParser<T> parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        this.parsedStatement = (ParsedStatementImpl<T>)parser.parse();
-        int numParams = parsedStatement.getNumParams();
-        params = new PreparedParameters(numParams);
-        Statement<T> statement = parsedStatement.getRawStatement();
-        if (statement instanceof DataModifyingStatement) {
-            this.dmlStatement = (DataModifyingStatement<T>) statement;
-        } else if (statement instanceof Query) {
-            this.query = (Query<T>) statement;
-        }
-    }
-    
-    // used for testing ParsedStatements
-    PreparedStatementImpl(int numParams) {
-        params = new PreparedParameters(numParams);
-        this.parsedStatement = null;
-    }
-    
-    @Override
-    public void setLong(int paramIndex, long paramValue) {
-        params.setLong(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setLongList(int paramIndex, long[] paramValue) {
-        params.setLongList(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setInt(int paramIndex, int paramValue) {
-        params.setInt(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setIntList(int paramIndex, int[] paramValue) {
-        params.setIntList(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setStringList(int paramIndex, String[] paramValue) {
-        params.setStringList(paramIndex, paramValue);
-    }
-    
-    @Override
-    public void setBoolean(int paramIndex, boolean paramValue) {
-        params.setBoolean(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setBooleanList(int paramIndex, boolean[] paramValue) {
-        params.setBooleanList(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setDouble(int paramIndex, double paramValue) {
-        params.setDouble(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setDoubleList(int paramIndex, double[] paramValue) {
-        params.setDoubleList(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setPojo(int paramIndex, Pojo paramValue) {
-        params.setPojo(paramIndex, paramValue);
-    }
-
-    @Override
-    public void setPojoList(int paramIndex, Pojo[] paramValue) {
-        params.setPojoList(paramIndex, paramValue);
-    }
-
-    @Override
-    public int execute() throws StatementExecutionException {
-        if (dmlStatement == null) {
-            throw new IllegalStateException(
-                    "Can't execute statement which isn't an instance of "
-                            + DataModifyingStatement.class.getName());
-        }
-        try {
-            dmlStatement = (DataModifyingStatement<T>)parsedStatement.patchStatement(params.getParams());
-        } catch (Exception e) {
-            throw new StatementExecutionException(e);
-        }
-        return dmlStatement.apply();
-    }
-
-    @Override
-    public Cursor<T> executeQuery() throws StatementExecutionException{
-        if (query == null) {
-            throw new IllegalStateException(
-                    "Can't execute statement which isn't an instance of "
-                            + Query.class.getName());
-        }
-        try {
-            // FIXME: I'm sure we can improve on this. We should avoid walking the
-            // tree each time. Some cache with unfinished nodes and a reference
-            // to the matching expression should be sufficient.
-            query = (Query<T>)parsedStatement.patchStatement(params.getParams());
-        } catch (IllegalPatchException e) {
-            throw new StatementExecutionException(e);
-        }
-        return query.execute();
-    }
-
-    @Override
-    public void setString(int paramIndex, String paramValue) {
-        params.setString(paramIndex, paramValue);
-    }
-    
-    // For testing only
-    PreparedParameter[] getParams() {
-        return params.getParams();
-    }
-
-    @Override
-    public ParsedStatement<T> getParsedStatement() {
-        return parsedStatement;
-    }
-
-    @Override
-    public String toString() {
-        return desc.getDescriptor();
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Printable.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.PreparedStatement;
-
-/**
- * Implement this interface for printable nodes in the
- * {@link PreparedStatement} parse tree. This is mainly useful for debugging
- * purposes. Most nodes of the prepared statement's parse tree implement it.
- * 
- *
- * @see SuffixExpression#printExpn();
- * @see WhereExpression#print(int);
- * @see SortExpression#print(int);
- * @see LimitExpression#print(int);
- */
-interface Printable {
-
-    /**
-     * Print a {@link Node} in a tree-like fashion.
-     * 
-     * @param level The level of this node in the tree.
-     */
-    void print(int level);
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SemanticsEnabledDescriptorParser.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.BackingStorage;
-import com.redhat.thermostat.storage.core.DataModifyingStatement;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-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.Statement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-
-class SemanticsEnabledDescriptorParser<T extends Pojo> extends
-        BasicDescriptorParser<T> {
-
-    SemanticsEnabledDescriptorParser(BackingStorage storage, StatementDescriptor<T> desc) {
-        super(storage, desc);
-    }
-    
-    public ParsedStatement<T> parse() throws DescriptorParsingException {
-        ParsedStatementImpl<T> parsed = (ParsedStatementImpl<T>)super.parse();
-        doSemanticAnalysis(parsed);
-        return parsed;
-    }
-    
-    private void doSemanticAnalysis(ParsedStatementImpl<T> parsed) throws DescriptorParsingException {
-        Statement<T> stmt = parsed.getRawStatement();
-        // statement should never be null
-        Objects.requireNonNull(stmt);
-        if (stmt instanceof Add) {
-            // ADD don't take a WHERE
-            if (tree.getWhereExpn() != null) {
-                String msg = "WHERE clause not allowed for ADD";
-                throw new DescriptorParsingException(msg);
-            }
-            // ADD requires all keys to be specified in the desc
-            ensureAllKeysSpecified();
-        }
-        if (stmt instanceof Replace) {
-            // REPLACE requires a WHERE
-            if (tree.getWhereExpn() == null) {
-                String msg = "WHERE clause required for REPLACE";
-                throw new DescriptorParsingException(msg);
-            }
-            // REPLACE requires all keys to be specified in the desc
-            ensureAllKeysSpecified();
-        }
-        if (stmt instanceof Update) {
-            // WHERE required for UPDATE
-            if (tree.getWhereExpn() == null) {
-                String msg = "WHERE clause required for UPDATE";
-                throw new DescriptorParsingException(msg);
-            }
-            // SET required for UPDATE
-            if (setList.getValues().size() == 0) {
-                String msg = "SET list required for UPDATE";
-                throw new DescriptorParsingException(msg);
-            }
-            ensureKeyInSetIsKnown();
-        }
-        if (stmt instanceof Remove && setList.getValues().size() > 0) {
-            String msg = "SET not allowed for REMOVE";
-            throw new DescriptorParsingException(msg);
-        }
-        // matches for QUERY/QUERY-COUNT/QUERY-DISTINCT
-        if (stmt instanceof Query) {
-            if (setList.getValues().size() > 0) {
-                // Must not have SET for QUERYs
-                String msg = "SET not allowed for QUERY/QUERY-COUNT";
-                throw new DescriptorParsingException(msg);
-            }
-            if (stmt instanceof AggregateQuery) {
-                AggregateQuery<T> aggQuery = (AggregateQuery<T>)stmt;
-                switch (aggQuery.getAggregateFunction()) {
-                case COUNT:
-                    // count queries need a sane key param if present
-                    performKeyParamChecksAllowNull(aggQuery);
-                    break;
-                case DISTINCT:
-                    // distinct queries must have a known key
-                    performKeyParamChecks(aggQuery);
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown aggregate function: " + aggQuery.getAggregateFunction());
-                }
-            }
-        } else {
-            assert(stmt instanceof DataModifyingStatement);
-            // only queries can have sort/limit expressions
-            if (this.tree.getLimitExpn() != null || this.tree.getSortExpn() != null) {
-                String msg = "LIMIT/SORT only allowed for QUERY/QUERY-COUNT";
-                throw new DescriptorParsingException(msg);
-            }
-        }
-    }
-
-    private void performKeyParamChecksAllowNull(AggregateQuery<T> aggQuery) throws DescriptorParsingException {
-        if (aggQuery.getAggregateKey() != null) {
-            performKeyParamChecks(aggQuery);
-        }
-    }
-
-    private void performKeyParamChecks(AggregateQuery<T> aggQuery) throws DescriptorParsingException {
-        Key<?> optionalKey = aggQuery.getAggregateKey();
-        if (optionalKey == null) {
-            throw new DescriptorParsingException("Aggregate key for " 
-                       + aggQuery.getAggregateFunction() + " must not be null.");
-        }
-        // non-null case
-        String name = optionalKey.getName();
-        Key<?> aggKey = desc.getCategory().getKey(name);
-        if (aggKey == null) {
-            throw new DescriptorParsingException("Unknown aggregate key '" + name + "'");
-        }
-    }
-
-    private void ensureKeyInSetIsKnown() throws DescriptorParsingException {
-        // retrieve the expected keys list from the category
-        Collection<Key<?>> keys = desc.getCategory().getKeys();
-        Set<Key<?>> expectedSet = new HashSet<>(keys.size());
-        expectedSet.addAll(keys);
-        List<String> unknownKeys = new ArrayList<>();
-        try {
-            for (SetListValue val: setList.getValues()) {
-                // this may throw CCE if LHS is a free parameter. That's not
-                // allowed though.
-                Key<?> key = (Key<?>)val.getKey().getValue();
-                if (!expectedSet.contains(key)) {
-                    unknownKeys.add(key.getName());
-                }
-            }
-        } catch (ClassCastException e) {
-            // LHS of set pair a free variable, which isn't allowed
-            String msg = "LHS of set list pair must not be a free variable.";
-            throw new DescriptorParsingException(msg);
-        }
-        if (!unknownKeys.isEmpty()) {
-            String msg = "Unknown key(s) in SET: '" + unknownKeys + "'";
-            throw new DescriptorParsingException(msg);
-        }
-    }
-
-    private void ensureAllKeysSpecified() throws DescriptorParsingException {
-        // retrieve the expected keys list from the category
-        Collection<Key<?>> keys = desc.getCategory().getKeys();
-        Set<Key<?>> expectedSet = new HashSet<>(keys.size());
-        expectedSet.addAll(keys);
-        Set<Key<?>> keysInSetList = new HashSet<>(keys.size());
-        try {
-            for (SetListValue val: setList.getValues()) {
-                // this may throw CCE
-                Key<?> key = (Key<?>)val.getKey().getValue();
-                keysInSetList.add(key);
-            }
-        } catch (ClassCastException e) {
-            // LHS of set pair a free variable, which isn't allowed
-            String msg = "LHS of set list pair must not be a free variable.";
-            throw new DescriptorParsingException(msg);
-        }
-        if (!keysInSetList.equals(expectedSet)) {
-            String msg = "Keys don't match keys in category. Expected the following keys: " + expectedSet + " got " + keysInSetList;
-            throw new DescriptorParsingException(msg);
-        };
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SetList.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-/**
- * Represents a set list of a prepared write statement.
- *
- */
-class SetList implements Patchable, Printable {
-
-    private List<SetListValue> values = new ArrayList<>();
-    
-    void addValue(SetListValue newValue) {
-        values.add(newValue);
-    }
-    
-    List<SetListValue> getValues() {
-        return values;
-    }
-
-    @Override
-    public void print(int level) {
-        System.out.println("SET:");
-        for (SetListValue val: getValues()) {
-            val.print(level);
-        }
-    }
-
-    @Override
-    public PatchedSetList patch(PreparedParameter[] params)
-            throws IllegalPatchException {
-        List<PatchedSetListMember> patchedSetList = new ArrayList<>();
-        for (SetListValue val: getValues()) {
-            PatchedSetListMemberExpression memberExp = val.patch(params);
-            patchedSetList.add(memberExp.getSetListMember());
-        }
-        PatchedSetListMember[] members = patchedSetList.toArray(new PatchedSetListMember[0]);
-        PatchedSetListImpl setList = new PatchedSetListImpl(members);
-        return setList;
-    }
-    
-    private static class PatchedSetListImpl implements PatchedSetList {
-
-        private final PatchedSetListMember[] members;
-        
-        private PatchedSetListImpl(PatchedSetListMember[] members) {
-            this.members = members;
-        }
-        
-        @Override
-        public PatchedSetListMember[] getSetListMembers() {
-            return members;
-        }
-        
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SetListValue.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.query.LiteralExpression;
-
-/**
- * Represents a value pair in a set list of prepared writes.
- *
- */
-class SetListValue implements Patchable, Printable {
-
-    private TerminalNode key;
-    private TerminalNode value;
-    
-    TerminalNode getKey() {
-        return key;
-    }
-    void setKey(TerminalNode key) {
-        this.key = key;
-    }
-    TerminalNode getValue() {
-        return value;
-    }
-    void setValue(TerminalNode value) {
-        this.value = value;
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof SetListValue)) {
-            return false;
-        }
-        SetListValue o = (SetListValue)other;
-        return Objects.equals(this.getValue(), o.getValue()) &&
-                Objects.equals(this.getKey(), o.getKey());
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(this.getKey(), this.getValue());
-    }
-    
-    @Override
-    public String toString() {
-        return "{" + getKey() + " = " + getValue() + "}";
-    }
-    
-    @Override
-    public void print(int level) {
-        for (int i = 0; i < level; i++) {
-            System.out.print(" ");
-        }
-        System.out.println(toString());
-        
-    }
-    
-    @Override
-    public PatchedSetListMemberExpression patch(PreparedParameter[] params)
-            throws IllegalPatchException {
-        
-        // patch LHS
-        PatchedWhereExpression keyExp = key.patch(params);
-        @SuppressWarnings("unchecked") // we've generated the key
-        LiteralExpression<Key<?>> keyLiteral = (LiteralExpression<Key<?>>)keyExp.getExpression();
-        Key<?> keyVal = (Key<?>) keyLiteral.getValue();
-        
-        // patch RHS
-        PatchedWhereExpression valExp = value.patch(params);
-        LiteralExpression<?> valLiteral = (LiteralExpression<?>)valExp.getExpression();
-        Object val = valLiteral.getValue();
-        
-        PatchedSetListMember member = new PatchedSetListMember(keyVal, val);
-        PatchedSetListMemberExpressionImpl retval = new PatchedSetListMemberExpressionImpl(member);
-        return retval;
-    }
-    
-    private static class PatchedSetListMemberExpressionImpl implements PatchedSetListMemberExpression {
-
-        private final PatchedSetListMember member;
-        
-        private PatchedSetListMemberExpressionImpl(PatchedSetListMember member) {
-            this.member = member;
-        }
-        
-        @Override
-        public PatchedSetListMember getSetListMember() {
-            return member;
-        }
-        
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-/**
- * Represents a sort expression of a prepared statement's parse tree.
- *
- */
-class SortExpression implements Printable, Patchable {
-    
-    List<SortMember> members = new ArrayList<>();
-    
-    public void addMember(SortMember member) {
-        members.add(member);
-    }
-    
-    public List<SortMember> getMembers() {
-        return members;
-    }
-
-    @Override
-    public void print(int level) {
-        System.out.print("SORT: ");
-        for (int i = 0; i < members.size(); i++) {
-            SortMember member = members.get(i);
-            member.print(level);
-            if (i < members.size() - 1) {
-                System.out.print(", ");
-            }
-        }
-        System.out.println("");
-    }
-
-    @Override
-    public PatchedSortExpression patch(PreparedParameter[] params)
-            throws IllegalPatchException {
-        List<PatchedSortMember> patchedMembers = new ArrayList<>();
-        for (SortMember member: members) {
-            PatchedSortMemberExpression expn = member.patch(params);
-            patchedMembers.add(expn.getSortMember());
-        }
-        // worked so far (no exceptions) create impl exp and return
-        PatchedSortMember[] members = patchedMembers.toArray(new PatchedSortMember[0]);
-        return new PatchedSortExpressionImpl(members);
-    }
-
-    private static class PatchedSortExpressionImpl implements PatchedSortExpression {
-
-        private final PatchedSortMember[] members;
-        
-        private PatchedSortExpressionImpl(PatchedSortMember[] members) {
-            this.members = members;
-        }
-        
-        @Override
-        public PatchedSortMember[] getSortMembers() {
-            return members;
-        }
-        
-        
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortMember.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
-
-/**
- * Represents sort members.
- * 
- * @see SortExpression
- *
- */
-class SortMember implements Printable, Patchable {
-
-    private SortDirection direction;
-    private Object sortKey;
-
-    public SortDirection getDirection() {
-        return direction;
-    }
-
-    public void setDirection(SortDirection direction) {
-        this.direction = direction;
-    }
-
-    public Object getSortKey() {
-        return sortKey;
-    }
-
-    public void setSortKey(Object sortKey) {
-        this.sortKey = sortKey;
-    }
-
-    @Override
-    public void print(int level) {
-        System.out.print(getSortKey() + " " + getDirection().name());
-    }
-
-    @Override
-    public PatchedSortMemberExpression patch(PreparedParameter[] params)
-            throws IllegalPatchException {
-        try {
-            String keyVal = null;
-            if (getSortKey() instanceof Unfinished) {
-                Unfinished unfinished = (Unfinished)getSortKey();
-                PreparedParameter p = params[unfinished.getParameterIndex()];
-                // Should only allow patching of ?s type NOT ?s[
-                if (p.getType() != String.class) {
-                    String msg = "Illegal parameter type for index "
-                            + unfinished.getParameterIndex()
-                            + ". Expected String!";
-                    IllegalArgumentException iae = new IllegalArgumentException(msg);
-                    throw iae;
-                }
-                keyVal = (String)p.getValue();
-            } else {
-                keyVal = (String)getSortKey();
-            }
-            Key<?> sortKey = new Key<>(keyVal);
-            PatchedSortMember m = new PatchedSortMember(sortKey, getDirection());
-            return new PatchedSortMemberExpressionImpl(m);
-        } catch (Exception e) {
-            throw new IllegalPatchException(e);
-        }
-    }
-    
-    private static class PatchedSortMemberExpressionImpl implements PatchedSortMemberExpression {
-        
-        private final PatchedSortMember member;
-        private PatchedSortMemberExpressionImpl(PatchedSortMember member) {
-            this.member = member;
-        }
-        
-        @Override
-        public PatchedSortMember getSortMember() {
-            return member;
-        }
-        
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/**
- * Common interface for statement descriptor parsers.
- * 
- * @see BasicDescriptorParser
- * @see SemanticsEnabledDescriptorParser
- *
- * @param <T> The {@link Pojo} model type pertaining to this parser. 
- */
-interface StatementDescriptorParser<T extends Pojo> {
-
-    /**
-     * Parses a descriptor, possibly performing some semantic analysis after
-     * parsing.
-     * 
-     * @throws DescriptorParsingException
-     *             if the descriptor failed to parse or did not pass semantic
-     *             analysis.
-     * @return An intermediary representation suitable for repeated execution of
-     *         the prepared statement.
-     */
-    ParsedStatement<T> parse() throws DescriptorParsingException;
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SuffixExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/**
- * Container for where, sort and limit expressions.
- *
- */
-class SuffixExpression {
-
-    private WhereExpression whereExpn;
-    private SortExpression sortExpn;
-    private LimitExpression limitExpn;
-
-    public WhereExpression getWhereExpn() {
-        return whereExpn;
-    }
-
-    public void setWhereExpn(WhereExpression whereExpn) {
-        this.whereExpn = whereExpn;
-    }
-
-    public SortExpression getSortExpn() {
-        return sortExpn;
-    }
-
-    public void setSortExpn(SortExpression sortExpn) {
-        this.sortExpn = sortExpn;
-    }
-
-    public LimitExpression getLimitExpn() {
-        return limitExpn;
-    }
-
-    public void setLimitExpn(LimitExpression limitExpn) {
-        this.limitExpn = limitExpn;
-    }
-
-    /**
-     * Prints the entire suffix expression to stdout.
-     */
-    public void printExpn() {
-        if (whereExpn != null) {
-            whereExpn.print(0);
-        }
-        if (sortExpn != null) {
-            sortExpn.print(0);
-        }
-        if (limitExpn != null) {
-            limitExpn.print(0);
-        }
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/TerminalNode.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.LiteralExpression;
-
-/**
- * Node representing a leaf node in the prepared statement parse tree.
- *
- */
-class TerminalNode extends Node {
-
-    TerminalNode(Node parent) {
-        super(parent);
-    }
-    
-    @Override
-    public PatchedWhereExpression patch(PreparedParameter[] params) throws IllegalPatchException {
-        if (getValue() == null) {
-            String msg = TerminalNode.class.getSimpleName() +
-                    " invalid when attempted to patch";
-            IllegalStateException cause = new IllegalStateException(msg);
-            throw new IllegalPatchException(cause);
-        }
-        Object actualValue;
-        if (getValue() instanceof UnfinishedValueNode) {
-            // need to patch the value
-            UnfinishedValueNode patch = (UnfinishedValueNode)getValue();
-            PreparedParameter param = null;
-            try {
-                param = params[patch.getParameterIndex()];
-            } catch (Exception e) {
-                throw new IllegalPatchException(e);
-            }
-            // Do some type sanity checking for free parameters
-            ensureTypeCompatibility(patch, param);
-            if (patch.isLHS()) {
-                // LHS need to get patched to keys
-                Key<?> valueKey = new Key<>((String)param.getValue());
-                actualValue = valueKey;
-            } else {
-                actualValue = param.getValue();
-            }
-        } else {
-            actualValue = getValue();
-        }
-        LiteralExpression<?> literalExp = new LiteralExpression<>(actualValue);
-        return new PatchedWhereExpressionImpl(literalExp);
-    }
-    
-    private void ensureTypeCompatibility(UnfinishedValueNode patch,
-            PreparedParameter param) throws IllegalPatchException {
-        if (patch.getType() == Pojo.class) {
-            // handle pojo case
-            Object value = param.getValue();
-            if (Pojo.class.isAssignableFrom(param.getType()) &&
-                    value != null && !value.getClass().isArray()) {
-                return; // pojo-type match: OK
-            }
-            // dead-end
-            IllegalArgumentException iae = constructIllegalArgumentException(patch, param);
-            throw new IllegalPatchException(iae);
-        } else if (patch.getType() == Pojo[].class) {
-            // handle pojo list case
-            Object value = param.getValue();
-            if (Pojo.class.isAssignableFrom(param.getType()) && value != null
-                    && value.getClass().isArray()) {
-                return; // pojo-list type match: OK
-            }
-        } else {
-            // primitive types or primitive list types
-            if (param.getType() != patch.getType()) {
-                IllegalArgumentException iae = constructIllegalArgumentException(patch, param);
-                throw new IllegalPatchException(iae);
-            }
-            // passed primitive (array) type check
-        }
-    }
-        
-    private IllegalArgumentException constructIllegalArgumentException(
-            UnfinishedValueNode patch, PreparedParameter param) {
-        Object value = param.getValue();
-        String paramArrayPrefix = "";
-        if (value != null && value.getClass().isArray()) {
-            paramArrayPrefix = "[";
-        }
-        String msg = TerminalNode.class.getSimpleName()
-                + " invalid type when attempting to patch. Expected "
-                + patch.getType().getName() + " but was "
-                + paramArrayPrefix + param.getType().getName();
-        IllegalArgumentException iae = new IllegalArgumentException(msg);
-        return iae;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (other == null) {
-            return false;
-        }
-        if (!(other instanceof TerminalNode)) {
-            return false;
-        }
-        TerminalNode o = (TerminalNode)other;
-        return Objects.equals(getValue(), o.getValue());
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(getValue());
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnaryExpressionNode.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/**
- * @see NotBooleanExpressionNode
- *
- */
-abstract class UnaryExpressionNode extends Node {
-
-    UnaryExpressionNode(Node parent) {
-        super(parent);
-    }
-    
-    public abstract Object getOperator();
-    
-    @Override
-    public void print(int level) {
-        Node value = (Node)getValue();
-        for (int i = 0; i < level; i++) {
-            System.out.print("-");
-        }
-        System.out.print("U: " + getOperator());
-        System.out.println("");
-        value.print(level++);
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/Unfinished.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/**
- * Marker interface for unfinished nodes in a prepared statement's parse tree.
- *
- */
-public interface Unfinished {
-
-    /**
-     * @return The index which contains the actual value of this unfinished
-     *         node.
-     */
-    int getParameterIndex();
-
-    /**
-     * Sets the index which should be used for indexing into the list of
-     * parameters which contains actual values.
-     * 
-     * @param parameterIndex
-     */
-    void setParameterIndex(int parameterIndex);
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedLimitValue.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/**
- * 
- * Represents an {@link Unfinished} limit value.
- * 
- * @see Patchable
- *
- */
-class UnfinishedLimitValue extends AbstractUnfinished {
-
-    private int parameterIndex = -1;
-
-    @Override
-    public int getParameterIndex() {
-        return parameterIndex;
-    }
-
-    @Override
-    public void setParameterIndex(int parameterIndex) {
-        this.parameterIndex = parameterIndex;
-    }
-    
-    @Override
-    public String toString() {
-        return "Unfinished limit value (" + getParameterIndex() + ")";
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedSortKey.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/**
- * 
- * Represents an {@link Unfinished} sort value.
- * 
- * @see Patchable
- *
- */
-class UnfinishedSortKey extends AbstractUnfinished {
-
-    private int paramIndex = -1;
-    
-    @Override
-    public int getParameterIndex() {
-        return paramIndex;
-    }
-
-    @Override
-    public void setParameterIndex(int parameterIndex) {
-        this.paramIndex = parameterIndex;
-    }
-    
-    @Override
-    public String toString() {
-        return "Unfinished sort key (" + getParameterIndex() + ")";
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedValueNode.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.Objects;
-
-/**
- * 
- * Represents an {@link Unfinished} node in the where expressions parse tree
- * of prepared statements.
- * 
- * @see Patchable
- *
- */
-class UnfinishedValueNode extends AbstractUnfinished {
-
-    private int parameterIndex = -1;
-    // determines if this patched value is a LHS or if false a RHS of a
-    // binary comparison.
-    private boolean isLHS;
-    // Specifies the expected (component) type of this free parameter.
-    private Class<?> type;
-
-    Class<?> getType() {
-        return type;
-    }
-
-    void setType(Class<?> type) {
-        this.type = type;
-    }
-
-    boolean isLHS() {
-        return isLHS;
-    }
-
-    void setLHS(boolean isLHS) {
-        this.isLHS = isLHS;
-    }
-
-    @Override
-    public int getParameterIndex() {
-        return parameterIndex;
-    }
-
-    @Override
-    public void setParameterIndex(int parameterIndex) {
-        this.parameterIndex = parameterIndex;
-    }
-
-    @Override
-    public String toString() {
-        return "Unfinished value (" + getParameterIndex() + ") " + getType() +
-                                 ":" + ( isLHS ? "LHS" : "RHS" );
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        boolean basics = super.equals(other);
-        if (!basics) {
-            return false;
-        }
-        if (!(other instanceof UnfinishedValueNode)) {
-            return false;
-        }
-        UnfinishedValueNode o = (UnfinishedValueNode)other;
-        return basics && Objects.equals(isLHS(), o.isLHS) &&
-                Objects.equals(getType(), o.getType());
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(getParameterIndex(), isLHS(), getType());
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/WhereExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-/**
- * Data structure representing a where expression.
- *
- * @see Node
- * @see SuffixExpression
- * @see BasicDescriptorParser
- */
-class WhereExpression implements Printable, Patchable {
-
-    private final Node root;
-    
-    WhereExpression() {
-        this.root = new Node(null);
-    }
-
-    public Node getRoot() {
-        return root;
-    }
-
-    @Override
-    public void print(int level) {
-        System.out.println("WHERE:");
-        Node node = (Node)root.getValue();
-        node.print(0);
-    }
-
-    @Override
-    public PatchedWhereExpression patch(PreparedParameter[] params)
-            throws IllegalPatchException {
-        Node node = (Node)root.getValue();
-        return node.patch(params);
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryComparisonExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import com.redhat.thermostat.storage.core.Key;
-
-/**
- * A {@link BinaryExpression} that corresponds to an algebraic comparison
- * between a {@link Key} and a corresponding value.
- * @param <T> - the type parameter of this expression's {@link Key}
- */
-public final class BinaryComparisonExpression<T>
-        extends BinaryExpression<LiteralExpression<Key<T>>, LiteralExpression<T>, BinaryComparisonOperator> 
-        implements ComparisonExpression {
-    
-    /**
-     * Constructs a {@link BinaryComparisonExpression} whose operands are
-     * a {@link LiteralExpression} for a {@link Key} and a {@link LiteralExpression}
-     * for the value to compare against the key.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param leftOperand - left operand for this expression
-     * @param operator - the operator for this expression
-     * @param rightOperand - right operand for this expression
-     */
-    public BinaryComparisonExpression(LiteralExpression<Key<T>> leftOperand,
-            BinaryComparisonOperator operator, LiteralExpression<T> rightOperand) {
-        super(leftOperand, operator, rightOperand);
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryComparisonOperator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Operators to be used with {@link BinaryComparisonExpression}
- */
-public enum BinaryComparisonOperator implements BinaryOperator {
-    /** Equality comparison */
-    EQUALS,
-    /** Inequality comparison */
-    NOT_EQUAL_TO,
-    /** Greater than comparison */
-    GREATER_THAN,
-    /** Greater than or equal comparison */
-    GREATER_THAN_OR_EQUAL_TO,
-    /** Less than comparison */
-    LESS_THAN,
-    /** Less than or equal comparison */
-    LESS_THAN_OR_EQUAL_TO,
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * An {@link Expression} with two operands and one operator.
- * @param <S> - the type of {@link Expression} corresponding to the left operand
- * @param <T> - the type of {@link Expression} corresponding to the right operand
- * @param <U> - the type of {@link BinaryOperator} corresponding to the operator
- */
-abstract class BinaryExpression<S extends Expression, T extends Expression, U extends BinaryOperator>
-        implements Expression {
-    
-    private S leftOperand;
-    private U operator;
-    private T rightOperand;
-    
-    /**
-     * Constructs a {@link BinaryExpression} given two operands and an operator.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param leftOperand - left operand for this expression
-     * @param operator - the operator for this expression
-     * @param rightOperand - right operand for this expression
-     */
-    BinaryExpression(S leftOperand, U operator, T rightOperand) {
-        this.leftOperand = leftOperand;
-        this.operator = operator;
-        this.rightOperand = rightOperand;
-    }
-    
-    /**
-     * @return the left operand of this expression
-     */
-    public S getLeftOperand() {
-        return leftOperand;
-    }
-    
-    /**
-     * @return the operator of this expression
-     */
-    public U getOperator() {
-        return operator;
-    }
-    
-    /**
-     * @return the right operand of this expression
-     */
-    public T getRightOperand() {
-        return rightOperand;
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        boolean result = false;
-        if (obj != null && obj instanceof BinaryExpression) {
-            BinaryExpression<?, ?, ?> otherExpr = (BinaryExpression<?, ?, ?>) obj;
-            result = leftOperand.equals(otherExpr.leftOperand)
-                    && rightOperand.equals(otherExpr.rightOperand)
-                    && operator.equals(otherExpr.operator);
-        }
-        return result;
-    }
-    
-    @Override
-    public int hashCode() {
-        return leftOperand.hashCode() + operator.hashCode() + rightOperand.hashCode();
-    }
-    
-    @Override
-    public String toString() {
-        StringBuilder buf = new StringBuilder();
-        buf.append("( ");
-        buf.append(leftOperand.toString());
-        buf.append(" ");
-        buf.append(operator.toString());
-        buf.append(" ");
-        buf.append(rightOperand.toString());
-        buf.append(" )");
-        return buf.toString();
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryLogicalExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * A {@link BinaryExpression} that represents a boolean formula
- * with two expressions joined by a logical operator.
- * @param <S> - the type of {@link Expression} corresponding to the left operand
- * @param <T> - the type of {@link Expression} corresponding to the right operand
- */
-public final class BinaryLogicalExpression<S extends Expression, T extends Expression>
-        extends BinaryExpression<S, T, BinaryLogicalOperator>
-        implements LogicalExpression {
-
-    /**
-     * Constructs a {@link BinaryLogicalExpression} whose operands are
-     * expressions joined by a {@link BinaryLogicalOperator}.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param leftOperand - left operand for this expression
-     * @param operator - the operator for this expression
-     * @param rightOperand - right operand for this expression
-     */
-    public BinaryLogicalExpression(S leftOperand, BinaryLogicalOperator operator, T rightOperand) {
-        super(leftOperand, operator, rightOperand);
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryLogicalOperator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Boolean operators to be used with {@link BinaryLogicalExpression}.
- */
-public enum BinaryLogicalOperator implements BinaryOperator {
-    /** Logical AND operation */
-    AND,
-    /** Logical OR operation */
-    OR,
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinaryOperator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Represents operators that take two operands.
- */
-interface BinaryOperator extends Operator {
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinarySetMembershipExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import com.redhat.thermostat.storage.core.Key;
-
-/**
- * A {@link BinaryExpression} that corresponds to an algebraic comparison
- * between a {@link Key} and multiple values.
- * @param <T> - the type parameter of this expression's {@link Key}
- */
-public final class BinarySetMembershipExpression<T>
-        extends BinaryExpression<LiteralExpression<Key<T>>, LiteralSetExpression<T>, BinarySetMembershipOperator>
-        implements ComparisonExpression {
-    
-    /**
-     * Constructs a {@link BinarySetMembershipExpression} whose operands are
-     * a {@link LiteralExpression} for a {@link Key} and a {@link LiteralSetExpression}
-     * for the set of values to compare against the key.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param leftOperand - left operand for this expression
-     * @param operator - the operator for this expression
-     * @param rightOperand - right operand for this expression
-     */
-    public BinarySetMembershipExpression(LiteralExpression<Key<T>> leftOperand,
-            BinarySetMembershipOperator operator, LiteralSetExpression<T> rightOperand) {
-        super(leftOperand, operator, rightOperand);
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/BinarySetMembershipOperator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Operators to be used with {@link BinarySetMembershipExpression}
- */
-public enum BinarySetMembershipOperator implements BinaryOperator {
-    /** Compares if the left-hand value is equal to any of the
-     *  right-hand values */
-    IN,
-    /** Compares if the left-hand value is not equal to all of the
-     *  right-hand values */
-    NOT_IN,
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/ComparisonExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-public interface ComparisonExpression extends Expression {
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/Expression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import com.redhat.thermostat.storage.core.Query;
-
-/**
- * Base interface for all expressions used in storage queries.
- * @see Query#where(Expression)
- */
-public interface Expression {
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/ExpressionFactory.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Query;
-
-/**
- * This class provides convenience methods that should be used
- * to create all expressions used in queries.
- * 
- * @see Expression
- * @see Query#where(Expression)
- */
-public class ExpressionFactory {
-    
-    /**
-     * Creates a {@link BinaryComparisonExpression} comparing the
-     * provided key and value for equality.
-     * @param key - {@link Key} whose value to compare against the provided value
-     * @param value - the value to compare against the key
-     * @return the new comparison expression
-     */
-    public <T> BinaryComparisonExpression<T> equalTo(Key<T> key, T value) {
-        return createComparisonExpression(key, value, BinaryComparisonOperator.EQUALS);
-    }
-    
-    /**
-     * Creates a {@link BinaryComparisonExpression} comparing the
-     * provided key and value for inequality.
-     * @param key - {@link Key} whose value to compare against the provided value
-     * @param value - the value to compare against the key
-     * @return the new comparison expression
-     */
-    public <T> BinaryComparisonExpression<T> notEqualTo(Key<T> key, T value) {
-        return createComparisonExpression(key, value, BinaryComparisonOperator.NOT_EQUAL_TO);
-    }
-    
-    /**
-     * Creates a {@link BinaryComparisonExpression} comparing if the
-     * provided key has a value greater than the provided value.
-     * @param key - {@link Key} whose value to compare against the provided value
-     * @param value - the value to compare against the key
-     * @return the new comparison expression
-     */
-    public <T> BinaryComparisonExpression<T> greaterThan(Key<T> key, T value) {
-        return createComparisonExpression(key, value, BinaryComparisonOperator.GREATER_THAN);
-    }
-    
-    /**
-     * Creates a {@link BinaryComparisonExpression} comparing if the
-     * provided key has a value less than the provided value.
-     * @param key - {@link Key} whose value to compare against the provided value
-     * @param value - the value to compare against the key
-     * @return the new comparison expression
-     */
-    public <T> BinaryComparisonExpression<T> lessThan(Key<T> key, T value) {
-        return createComparisonExpression(key, value, BinaryComparisonOperator.LESS_THAN);
-    }
-    
-    /**
-     * Creates a {@link BinaryComparisonExpression} comparing if the
-     * provided key has a value greater than or equal to the provided value.
-     * @param key - {@link Key} whose value to compare against the provided value
-     * @param value - the value to compare against the key
-     * @return the new comparison expression
-     */
-    public <T> BinaryComparisonExpression<T> greaterThanOrEqualTo(Key<T> key, T value) {
-        return createComparisonExpression(key, value, BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-    }
-    
-    /**
-     * Creates a {@link BinaryComparisonExpression} comparing if the
-     * provided key has a value less than or equal to the provided value.
-     * @param key - {@link Key} whose value to compare against the provided value
-     * @param value - the value to compare against the key
-     * @return the new comparison expression
-     */
-    public <T> BinaryComparisonExpression<T> lessThanOrEqualTo(Key<T> key, T value) {
-        return createComparisonExpression(key, value, BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-    }
-    
-    /**
-     * Creates a {@link BinarySetMembershipExpression} comparing if the
-     * provided key has a value equal to any of the provided values.
-     * @param key - {@link Key} whose value to compare against the provided values
-     * @param value - a set of values to compare against the key
-     * @param type - the type of values of stored in the provided set
-     * @return the new comparison expression
-     */
-    public <T> BinarySetMembershipExpression<T> in(Key<T> key, Set<T> values, Class<T> type) {
-        return createSetMembershipExpression(key, values, BinarySetMembershipOperator.IN, type);
-    }
-    
-    /**
-     * Creates a {@link BinarySetMembershipExpression} comparing if the
-     * provided key has a value not equal to all of the provided values.
-     * @param key - {@link Key} whose value to compare against the provided values
-     * @param value - a set of values to compare against the key
-     * @param type - the type of values of stored in the provided set
-     * @return the new comparison expression
-     */
-    public <T> BinarySetMembershipExpression<T> notIn(Key<T> key, Set<T> values, Class<T> type) {
-        return createSetMembershipExpression(key, values, BinarySetMembershipOperator.NOT_IN, type);
-    }
-    
-    /**
-     * Creates a {@link UnaryLogicalExpression} which is a logical
-     * negation of the provided expression.
-     * @param expr - the expression to negate
-     * @return the new negated expression
-     */
-    public <T extends ComparisonExpression> UnaryLogicalExpression<T> not(T expr) {
-        return new UnaryLogicalExpression<>(expr, UnaryLogicalOperator.NOT);
-    }
-    
-    /**
-     * Creates a {@link BinaryLogicalExpression} with the two provided expressions
-     * joined in order by a logical AND operation.
-     * @param left - the left operand
-     * @param right - the right operand
-     * @return the new logical expression
-     */
-    public <S extends Expression, T extends Expression> BinaryLogicalExpression<S, T> and(S left, T right) {
-        return new BinaryLogicalExpression<S, T>(left, BinaryLogicalOperator.AND, right);
-    }
-    
-    /**
-     * Creates a {@link BinaryLogicalExpression} with the two provided expressions
-     * joined in order by a logical OR operation.
-     * @param left - the left operand
-     * @param right - the right operand
-     * @return the new logical expression
-     */
-    public <S extends Expression, T extends Expression> BinaryLogicalExpression<S, T> or(S left, T right) {
-        return new BinaryLogicalExpression<S, T>(left, BinaryLogicalOperator.OR, right);
-    }
-    
-    private <T> BinaryComparisonExpression<T> createComparisonExpression(Key<T> key, T value, BinaryComparisonOperator op) {
-        return new BinaryComparisonExpression<>(new LiteralExpression<>(key), op, new LiteralExpression<>(value));
-    }
-    
-    private <T> BinarySetMembershipExpression<T> createSetMembershipExpression(Key<T> key, Set<T> values,
-            BinarySetMembershipOperator op, Class<T> type) {
-        return new BinarySetMembershipExpression<>(new LiteralExpression<>(key), op, 
-                new LiteralSetExpression<>(values, type));
-    }
-    
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/LiteralExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * An {@link Expression} that contains a value.
- * @param <T> - the type of this expression's value
- */
-public final class LiteralExpression<T> implements Expression {
-
-    private T value;
-    
-    /**
-     * Constructs a {@link LiteralExpression} given a value.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param value - the value for this expression
-     */
-    public LiteralExpression(T value) {
-        this.value = value;
-    }
-    
-    /**
-     * @return the value represented by this expression
-     */
-    public T getValue() {
-        return value;
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        boolean result = false;
-        if (obj != null && obj instanceof LiteralExpression) {
-            LiteralExpression<?> otherExpr = (LiteralExpression<?>) obj;
-            result = value.equals(otherExpr.value);
-        }
-        return result;
-    }
-    
-    @Override
-    public int hashCode() {
-        return value.hashCode();
-    }
-    
-    @Override
-    public String toString() {
-        return value.toString();
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/LiteralSetExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * An {@link Expression} that contains a set of values.
- * @param <T> - the type of this expression's values
- */
-public final class LiteralSetExpression<T> implements Expression {
-
-    private Set<T> values;
-    private Class<T> type;
-    
-    /**
-     * Constructs a {@link LiteralSetExpression} given a list of values
-     * and its type.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param values - a list of values for this expression
-     * @param type - the type of values of stored in the provided set
-     * (needed for serialization)
-     */
-    public LiteralSetExpression(Set<T> values, Class<T> type) {
-        // Don't need to write, make read-only copy
-        this.values = Collections.unmodifiableSet(values);
-        this.type = type;
-    }
-    
-    /**
-     * @return the values represented by this expression
-     */
-    public Set<T> getValues() {
-        return values;
-    }
-    
-    /**
-     * @return the type of values stored in this expression
-     */
-    public Class<T> getType() {
-        return type;
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        boolean result = false;
-        if (obj != null && obj instanceof LiteralSetExpression) {
-            LiteralSetExpression<?> otherExpr = (LiteralSetExpression<?>) obj;
-            result = values.equals(otherExpr.values)
-                    && type.equals(otherExpr.type);
-        }
-        return result;
-    }
-    
-    @Override
-    public int hashCode() {
-        return values.hashCode() + type.hashCode();
-    }
-    
-    @Override
-    public String toString() {
-        return values.toString();
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/LogicalExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-public interface LogicalExpression extends Expression {
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/Operator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Base interface for operators that are used with {@link Expression} objects.
- * Concrete implementations must be enumeration types.
- */
-public interface Operator {
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * An {@link Expression} that has an operator and one operand.
- * @param <S> - type of {@link Expression} used for the operand
- * @param <T> - type of {@link UnaryOperator} used for the operator
- */
-abstract class UnaryExpression<S extends Expression, T extends UnaryOperator> implements Expression {
-    
-    private S operand;
-    private T operator;
-    
-    /**
-     * Constructs a {@link UnaryExpression} given an operand and an operator.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param operand - operand for this expression
-     * @param operator - operator for this expression
-     */
-    UnaryExpression(S operand, T operator) {
-        this.operand = operand;
-        this.operator = operator;
-    }
-    
-    /**
-     * @return the operand for this expression
-     */
-    public S getOperand() {
-        return operand;
-    }
-    
-    /**
-     * @return the operator for this expression
-     */
-    public T getOperator() {
-        return operator;
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        boolean result = false;
-        if (obj != null && obj instanceof UnaryExpression) {
-            UnaryExpression<?, ?> otherExpr = (UnaryExpression<?, ?>) obj;
-            result = operand.equals(otherExpr.operand)
-                    && operator.equals(otherExpr.operator);
-        }
-        return result;
-    }
-    
-    @Override
-    public int hashCode() {
-        return operand.hashCode() + operator.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder buf = new StringBuilder();
-        buf.append("( ");
-        buf.append(operator.toString());
-        buf.append(" ");
-        buf.append(operand.toString());
-        buf.append(" )");
-        return buf.toString();
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryLogicalExpression.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * A {@link UnaryExpression} which represents a boolean formula
- * with one comparison expression and a logical operator.
- * @param <T> - type of {@link Expression} used for the operand
- */
-public final class UnaryLogicalExpression<T extends ComparisonExpression> extends
-        UnaryExpression<T, UnaryLogicalOperator>
-        implements LogicalExpression {
-
-    /**
-     * Constructs a {@link UnaryLogicalExpression} given an operand
-     * and a {@link UnaryLogicalOperator}.
-     * <p>
-     * This constructor exists mainly for JSON serialization, use methods in
-     * {@link ExpressionFactory} instead of this constructor.
-     * @param operand - the operand for this expression
-     * @param operator - the operator for this expression
-     */
-    public UnaryLogicalExpression(T operand, UnaryLogicalOperator operator) {
-        super(operand, operator);
-    }
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryLogicalOperator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Operators to be used with {@link UnaryLogicalExpression}.
- */
-public enum UnaryLogicalOperator implements UnaryOperator {
-    /** Logical NOT operation */
-    NOT,
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/query/UnaryOperator.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-/**
- * Represents operators that take one operand.
- */
-interface UnaryOperator extends Operator {
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/AggregateQueryTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-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.Statement;
-import com.redhat.thermostat.storage.model.AggregateCount;
-
-public class AggregateQueryTest {
-
-    @Test
-    public void testSetAggregateKey() {
-        @SuppressWarnings("unchecked")
-        Query<AggregateCount> query = mock(Query.class);
-        TestAggregateQuery aggregate = new TestAggregateQuery(AggregateFunction.COUNT, query);
-        assertNull(aggregate.getAggregateKey());
-        try {
-            aggregate.setAggregateKey(null);
-            fail("Expected NPE.");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        @SuppressWarnings("rawtypes")
-        Key<?> fooKey = new Key("foo");
-        aggregate.setAggregateKey(fooKey);
-        assertEquals(fooKey, aggregate.getAggregateKey());
-    }
-    
-    private static class TestAggregateQuery extends AggregateQuery<AggregateCount> {
-
-        public TestAggregateQuery(
-                AggregateFunction function,
-                Query<AggregateCount> queryToAggregate) {
-            super(function, queryToAggregate);
-        }
-
-        @Override
-        public Cursor<AggregateCount> execute() {
-            throw new AssertionError("not implemented");
-        }
-
-        @Override
-        public Statement<AggregateCount> getRawDuplicate() {
-            throw new AssertionError("not implemented");
-        }
-        
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/HostBoundaryPojoGetterTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-public class HostBoundaryPojoGetterTest {
-    private static final String AGENT_ID = "agentid";
-    private static final String HOSTNAME = "host.example.com";
-    private static final String CATEGORY_NAME = "host-boundary-category";
-    // Make this one static so we don't get IllegalStateException from trying
-    // to make category of same name while running tests in same classloader.
-    private static final Category<TestPojo> cat = new Category<>(CATEGORY_NAME, TestPojo.class);
-
-    private static long t1 = 1;
-    private static long t2 = 5;
-
-    private static long lc1 = 10;
-    private static long lc2 = 20;
-
-    private HostRef hostRef;
-    private AgentId agentId;
-    private TestPojo result1, result2;
-
-    @Before
-    public void setUp() {
-        hostRef = new HostRef(AGENT_ID, HOSTNAME);
-        agentId = new AgentId(AGENT_ID);
-        result1 = mock(TestPojo.class);
-        when(result1.getTimeStamp()).thenReturn(t1);
-        when(result1.getData()).thenReturn(lc1);
-        result2 = mock(TestPojo.class);
-        when(result2.getTimeStamp()).thenReturn(t2);
-        when(result2.getData()).thenReturn(lc2);
-    }
-
-    @Test
-    public void verifyLatestQueryDescriptorFormat() {
-        String newestExpected = "QUERY %s WHERE 'agentId' = ?s SORT 'timeStamp' DSC LIMIT 1";
-        assertEquals(newestExpected, HostBoundaryPojoGetter.DESC_NEWEST_HOST_STAT);
-    }
-
-    @Test
-    public void verifyOldestQueryDescriptorFormat() {
-        String oldestExpected = "QUERY %s WHERE 'agentId' = ?s SORT 'timeStamp' ASC LIMIT 1";
-        assertEquals(oldestExpected, HostBoundaryPojoGetter.DESC_OLDEST_HOST_STAT);
-    }
-
-    @Test
-    public void verifyLatestQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        HostBoundaryPojoGetter<TestPojo> getter = new HostBoundaryPojoGetter<>(storage, cat);
-
-        String actualLatestDesc = getter.getNewestQueryDesc();
-        String latestExpected = "QUERY host-boundary-category WHERE 'agentId' = ?s SORT 'timeStamp' DSC LIMIT 1";
-        assertEquals(latestExpected, actualLatestDesc);
-    }
-
-    @Test
-    public void verifyOldestQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        HostBoundaryPojoGetter<TestPojo> getter = new HostBoundaryPojoGetter<>(storage, cat);
-
-        String actualOldestDesc = getter.getOldestQueryDesc();
-        String oldestExpected = "QUERY host-boundary-category WHERE 'agentId' = ?s SORT 'timeStamp' ASC LIMIT 1";
-
-        assertEquals(oldestExpected, actualOldestDesc);
-    }
-
-    @Test
-    public void testHostRefGetOldest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        HostBoundaryPojoGetter<TestPojo> getter = new HostBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo oldest = getter.getOldestStat(hostRef);
-
-        assertEquals(t1, oldest.getTimeStamp());
-        assertEquals(lc1, oldest.getData());
-    }
-
-    @Test
-    public void testGetOldest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        HostBoundaryPojoGetter<TestPojo> getter = new HostBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo oldest = getter.getOldestStat(agentId);
-
-        assertEquals(t1, oldest.getTimeStamp());
-        assertEquals(lc1, oldest.getData());
-    }
-
-    @Test
-    public void testHostRefGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result2).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        HostBoundaryPojoGetter<TestPojo> getter = new HostBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo newest = getter.getNewestStat(hostRef);
-
-        assertEquals(t2, newest.getTimeStamp());
-        assertEquals(lc2, newest.getData());
-    }
-
-    @Test
-    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result2).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        HostBoundaryPojoGetter<TestPojo> getter = new HostBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo newest = getter.getNewestStat(agentId);
-
-        assertEquals(t2, newest.getTimeStamp());
-        assertEquals(lc2, newest.getData());
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<TestPojo> anyDescriptor() {
-        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
-    }
-
-    private static interface TestPojo extends TimeStampedPojo {
-        long getData();
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-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;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-public class HostLatestPojoListGetterTest {
-    private static final String AGENT_ID = "agentid";
-    private static final String HOSTNAME = "host.example.com";
-    private static final String CATEGORY_NAME = "hostcategory";
-    // Make this one static so we don't get IllegalStateException from trying
-    // to make category of same name while running tests in same classloader.
-    private static final Category<TestPojo> cat = new Category<>(CATEGORY_NAME, TestPojo.class);
-
-    private static long t1 = 1;
-    private static long t2 = 5;
-    private static long t3 = 10;
-
-    private static Double load5_1 = 2.0;
-    private static Double load5_2 = 6.0;
-    private static Double load5_3 = 11.0;
-
-    private static Double load10_1 = 3.0;
-    private static Double load10_2 = 7.0;
-    private static Double load10_3 = 12.0;
-
-    private static Double load15_1 = 4.0;
-    private static Double load15_2 = 8.0;
-    private static Double load15_3 = 13.0;
-
-    private HostRef ref;
-    private AgentId agentId;
-    private TestPojo result1, result2, result3;
-
-    @Before
-    public void setUp() {
-        final double[] d1 = new double[]{load5_1, load10_1, load15_1};
-        final double[] d2 = new double[]{load5_2, load10_2, load15_2};
-        final double[] d3 = new double[]{load5_3, load10_3, load15_3};
-        ref = new HostRef(AGENT_ID, HOSTNAME);
-        agentId = new AgentId(AGENT_ID);
-        result1 = mock(TestPojo.class);
-        when(result1.getTimeStamp()).thenReturn(t1);
-        when(result1.getData()).thenReturn(d1);
-        result2 = mock(TestPojo.class);
-        when(result2.getTimeStamp()).thenReturn(t2);
-        when(result2.getData()).thenReturn(d2);
-        result3 = mock(TestPojo.class);
-        when(result3.getTimeStamp()).thenReturn(t3);
-        when(result3.getData()).thenReturn(d3);
-    }
-
-    @Test
-    public void verifyQueryDescriptorFormat() {
-        String expected = "QUERY %s WHERE 'agentId' = ?s AND " +
-                "'timeStamp' > ?l SORT 'timeStamp' DSC";
-        assertEquals(expected, HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT);
-    }
-
-    @Test
-    public void verifyQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
-        String actualDesc = getter.getQueryLatestDesc();
-        String expected = "QUERY hostcategory WHERE 'agentId' = ?s AND " +
-                "'timeStamp' > ?l SORT 'timeStamp' DSC";
-        assertEquals(expected, actualDesc);
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<TestPojo> anyDescriptor() {
-        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
-    }
-
-    @Test
-    public void testHostRefGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        @SuppressWarnings("unchecked")
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
-
-        List<TestPojo> stats = getter.getLatest(ref, Long.MIN_VALUE);
-
-        assertNotNull(stats);
-        assertEquals(2, stats.size());
-        TestPojo stat1 = stats.get(0);
-        assertEquals(t1, stat1.getTimeStamp());
-        assertArrayEquals(new double[]{load5_1, load10_1, load15_1}, stat1.getData(), 0.001);
-        TestPojo stat2 = stats.get(1);
-        assertEquals(t2, stat2.getTimeStamp());
-        assertArrayEquals(new double[]{load5_2, load10_2, load15_2}, stat2.getData(), 0.001);
-    }
-
-    @Test
-    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        @SuppressWarnings("unchecked")
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
-
-        List<TestPojo> stats = getter.getLatest(agentId, Long.MIN_VALUE);
-
-        assertNotNull(stats);
-        assertEquals(2, stats.size());
-        TestPojo stat1 = stats.get(0);
-        assertEquals(t1, stat1.getTimeStamp());
-        assertArrayEquals(new double[]{load5_1, load10_1, load15_1}, stat1.getData(), 0.001);
-        TestPojo stat2 = stats.get(1);
-        assertEquals(t2, stat2.getTimeStamp());
-        assertArrayEquals(new double[]{load5_2, load10_2, load15_2}, stat2.getData(), 0.001);
-    }
-
-    @After
-    public void tearDown() {
-        ref = null;
-        result1 = null;
-        result2 = null;
-        result3 = null;
-    }
-
-    private static interface TestPojo extends TimeStampedPojo {
-
-        double[] getData();
-
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/PreparedParamentersTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class PreparedParamentersTest {
-
-    @Test
-    public void cannotSetNullPojo() {
-        PreparedParameters params = new PreparedParameters(1);
-        try {
-            params.setPojo(0, null);
-            fail("should not be able to set null Pojo");
-        } catch (NullPointerException e) {
-            // passs
-        }
-    }
-    
-    @Test
-    public void cannotSetNullPojoList() {
-        PreparedParameters params = new PreparedParameters(1);
-        try {
-            params.setPojoList(0, null);
-            fail("should not be able to set null Pojo list");
-        } catch (NullPointerException e) {
-            // passs
-        }
-    }
-    
-    @Test
-    public void canSetPojoType() {
-        PreparedParameters params = new PreparedParameters(1);
-        AgentInformation info = new AgentInformation(); 
-        params.setPojo(0, info);
-        assertEquals(AgentInformation.class, params.getParams()[0].getType());
-        assertEquals(info, params.getParams()[0].getValue());
-    }
-    
-    @Test
-    public void canSetPojoListType() {
-        PreparedParameters params = new PreparedParameters(1);
-        AgentInformation info = new AgentInformation();
-        params.setPojoList(0, new AgentInformation[] { info });
-        PreparedParameter p = params.getParams()[0];
-        assertEquals("Type should be component type", AgentInformation.class, p.getType());
-        assertEquals(info, ((AgentInformation[])p.getValue())[0]);
-    }
-    
-    @Test
-    public void testTypeInt() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setInt(0, -1);
-        assertEquals(int.class, params.getParams()[0].getType());
-    }
-    
-    @Test
-    public void testTypeIntList() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setIntList(0, new int[] { -1 });
-        assertEquals(int[].class, params.getParams()[0].getType());
-    }
-    
-    @Test
-    public void testTypeLong() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setLong(0, -1);
-        assertEquals(long.class, params.getParams()[0].getType());
-    }
-    
-    @Test
-    public void testTypeLongList() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setLongList(0, new long[] { -1 });
-        assertEquals(long[].class, params.getParams()[0].getType());
-    }
-    
-    @Test
-    public void testTypeBoolList() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setBooleanList(0, new boolean[] { true } );
-        assertEquals(boolean[].class, params.getParams()[0].getType());
-    }
-    
-    @Test
-    public void testTypeDouble() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setDouble(0, Math.E);
-        assertEquals(double.class, params.getParams()[0].getType());
-    }
-    
-    @Test
-    public void testTypeDoubleList() {
-        PreparedParameters params = new PreparedParameters(1);
-        params.setDoubleList(0, new double[] { Math.E });
-        assertEquals(double[].class, params.getParams()[0].getType());
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,641 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-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.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import java.io.InputStream;
-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 org.mockito.Mockito;
-
-import com.redhat.thermostat.common.Constants;
-import com.redhat.thermostat.storage.core.QueuedStorage.QueuedParsedStatement;
-import com.redhat.thermostat.storage.core.QueuedStorage.QueuedPreparedStatement;
-import com.redhat.thermostat.storage.core.QueuedStorage.QueuedWrite;
-import com.redhat.thermostat.storage.model.Pojo;
-
-
-public class QueuedStorageTest {
-
-    private static class TestExecutor implements ExecutorService {
-
-        private Runnable task;
-        private boolean shutdown;
-        private long awaitTerminationTimeout;
-        private TimeUnit awaitTerminationTimeUnit;
-
-        @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 {
-            awaitTerminationTimeout = timeout;
-            awaitTerminationTimeUnit = unit;
-            return true;
-        }
-
-        long getAwaitTerminationTimeout() {
-            return awaitTerminationTimeout;
-        }
-
-        TimeUnit getAwaitTerminationTimeUnit() {
-            return awaitTerminationTimeUnit;
-        }
-
-        @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 static class TestShutdownExecutor extends TestExecutor {
-        long executorShutDownTime = -1;
-        
-        @Override
-        public void shutdown() {
-            super.shutdown();
-            executorShutDownTime = System.currentTimeMillis();
-            // delay shutdown just a little
-            try {
-                Thread.sleep(10);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            }
-        }
-    }
-    
-    private static final Category<FooPojo> TEST_CATEGORY = new Category<>("foo-table", FooPojo.class);
-
-    private QueuedStorage queuedStorage;
-    private Storage delegateStorage;
-    
-    private TestExecutor executor;
-    private TestExecutor fileExecutor;
-
-    private InputStream expectedFile;
-
-    @Before
-    public void setUp() {
-        executor = new TestExecutor();
-        fileExecutor = new TestExecutor();
-        delegateStorage = mock(Storage.class);
-
-        expectedFile = mock(InputStream.class);
-        when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile);
-        queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor, null);
-    }
-
-    @After
-    public void tearDown() {
-        System.clearProperty(Constants.IS_PROXIED_STORAGE);
-        expectedFile = null;
-        queuedStorage = null;
-        delegateStorage = null;
-        fileExecutor = null;
-        executor = null;
-    }
-    
-    @Test
-    public void testPurge() {
-
-        queuedStorage.purge("fluff");
-
-        Runnable r = executor.getTask();
-        assertNotNull(r);
-        verifyZeroInteractions(delegateStorage);
-        r.run();
-        verify(delegateStorage, times(1)).purge("fluff");
-        verifyNoMoreInteractions(delegateStorage);
-
-        assertNull(fileExecutor.getTask());
-    }
-
-    @Test
-    public void testSaveFile() {
-        InputStream stream = mock(InputStream.class);
-        SaveFileListener listener = mock(SaveFileListener.class);
-
-        queuedStorage.saveFile("fluff", stream, listener);
-
-        Runnable task = fileExecutor.getTask();
-        assertNotNull(task);
-        verifyZeroInteractions(delegateStorage);
-        task.run();
-        verify(delegateStorage).saveFile(eq("fluff"), same(stream), same(listener));
-
-        assertNull(executor.getTask());
-    }
-
-    @Test
-    public void testLoadFile() {
-
-        InputStream stream = queuedStorage.loadFile("fluff");
-
-        assertSame(expectedFile, stream);
-
-        assertNull(executor.getTask());
-        assertNull(fileExecutor.getTask());
-    }
-    
-    /*
-     * For backing storage (i.e. a mongo delegate) and a proxy in front
-     * we should decorate PreparedStatement.execute(),
-     * PreparedStatement.executeQuery() and PreparedStatement.getParsedStatement().
-     * However, execute() and executeQuery() must not be called and it is not
-     * called. In that case the queueing is achieved via the decoration of
-     * PreparedStatement.getParsedStatement().
-     */
-    @Test
-    public void testPrepareStatementBackingNotProxied() throws DescriptorParsingException, StatementExecutionException, IllegalPatchException {
-        assertFalse("Precondition not secure storage FAILED!", delegateStorage instanceof SecureStorage);
-        System.setProperty(Constants.IS_PROXIED_STORAGE, Boolean.TRUE.toString());
-        queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor);
-        
-        @SuppressWarnings("unchecked")
-        PreparedStatement<Pojo> statement = (PreparedStatement<Pojo>)mock(PreparedStatement.class);
-        when(delegateStorage.prepareStatement(anyStatementDescriptor())).thenReturn(statement);
-        @SuppressWarnings("unchecked")
-        ParsedStatement<Pojo> mockParsedStatement = (ParsedStatement<Pojo>)mock(ParsedStatement.class);
-        when(statement.getParsedStatement()).thenReturn(mockParsedStatement);
-        @SuppressWarnings("unchecked")
-        DataModifyingStatement<Pojo> mockDms = (DataModifyingStatement<Pojo>)mock(DataModifyingStatement.class);
-        @SuppressWarnings("unchecked")
-        Query<Pojo> mockQuery = (Query<Pojo>)mock(Query.class);
-        // First return a write then a query
-        when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockDms).thenReturn(mockQuery);
-        
-        
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(TEST_CATEGORY, "QUERY foo-table");
-        PreparedStatement<FooPojo> decorated = queuedStorage.prepareStatement(desc);
-        assertNotNull(decorated);
-        assertTrue(decorated instanceof QueuedPreparedStatement);
-        assertNotSame(decorated, statement);
-        assertNull(executor.getTask());
-        QueuedPreparedStatement<FooPojo> stmt = (QueuedPreparedStatement<FooPojo>)decorated;
-        
-        // make sure execution of PreparedStatement.execute() and
-        // PreparedStatement.executeQuery() throws assertionError.
-        verifyAssertionError(stmt);
-        
-        // be sure that getParsedStatement returns a QueuedParsedStatement
-        ParsedStatement<FooPojo> parsed = stmt.getParsedStatement();
-        assertNotNull(parsed);
-        assertTrue(parsed instanceof QueuedParsedStatement);
-        QueuedParsedStatement<FooPojo> qParsed = (QueuedParsedStatement<FooPojo>)parsed;
-        // we should get a write first
-        Statement<FooPojo> patched = qParsed.patchStatement(new PreparedParameter[]{});
-        assertTrue(patched instanceof QueuedWrite);
-        QueuedWrite<FooPojo> qWrite = (QueuedWrite<FooPojo>)patched;
-        assertNull(executor.getTask());
-        qWrite.apply();
-        assertNotNull(executor.getTask());
-        // run the task
-        executor.getTask().run();
-        verify(mockDms).apply();
-        verifyNoMoreInteractions(mockDms);
-        // reset
-        executor.execute(null);
-        
-        // now do it again with a query
-        patched = qParsed.patchStatement(new PreparedParameter[]{});
-        assertTrue(patched instanceof Query);
-        Query<FooPojo> query = (Query<FooPojo>)patched;
-        assertNull(executor.getTask());
-        assertSame("Didn't expect query to get decorated", mockQuery, query);
-        query.execute();
-        assertNull("should not have submited to executor", executor.getTask());
-        verify(mockQuery).execute();
-        verifyNoMoreInteractions(mockQuery);
-    }
-    
-    private <T extends Pojo> void verifyAssertionError(QueuedPreparedStatement<T> decorated) throws StatementExecutionException {
-        try {
-            decorated.execute();
-            // throw something not an assertion error
-            throw new IllegalStateException("test failed");
-        } catch (AssertionError e) {
-            assertTrue(e.getMessage().contains("backing storage"));
-        }
-        try {
-            decorated.executeQuery();
-            // throw something not an assertion error
-            throw new IllegalStateException("test failed");
-        } catch (AssertionError e) {
-            assertTrue(e.getMessage().contains("backing storage"));
-        }
-    }
-    
-    /*
-     * For proxied storage (i.e. a web delegate) we should only decorate
-     * PreparedStatement.execute() and PreparedStatement.executeQuery() rather
-     * than also decorating PreparedStatement.getParsedStatement(). If we did
-     * both, we'd queue things twice.
-     */
-    @Test
-    public void testPrepareStatementProxied() throws DescriptorParsingException, StatementExecutionException, IllegalPatchException {
-        assertFalse(delegateStorage instanceof SecureStorage);
-        delegateStorage = mock(SecureStorage.class);
-        System.setProperty(Constants.IS_PROXIED_STORAGE, Boolean.TRUE.toString());
-        assertTrue("Precondition secure storage FAILED!", delegateStorage instanceof SecureStorage);
-        queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor);
-        
-        verifyDirectStorage();
-    }
-    
-    /*
-     * For backing storage used directly (i.e. a mongo delegate with *no* proxy storage in front) we should only decorate
-     * PreparedStatement.execute() and PreparedStatement.executeQuery() rather
-     * than also decorating PreparedStatement.getParsedStatement(). If we did
-     * both, we'd queue things twice.
-     */
-    @Test
-    public void testPrepareStatementBackingNoProxy() throws DescriptorParsingException, StatementExecutionException, IllegalPatchException {
-        assertFalse(delegateStorage instanceof SecureStorage);
-        System.setProperty(Constants.IS_PROXIED_STORAGE, Boolean.FALSE.toString());
-        queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor);
-        
-        verifyDirectStorage();
-    }
-    
-    private void verifyDirectStorage() throws DescriptorParsingException, StatementExecutionException, IllegalPatchException {
-        @SuppressWarnings("unchecked")
-        PreparedStatement<Pojo> statement = (PreparedStatement<Pojo>)mock(PreparedStatement.class);
-        when(delegateStorage.prepareStatement(anyStatementDescriptor())).thenReturn(statement);
-        @SuppressWarnings("unchecked")
-        ParsedStatement<Pojo> mockParsedStatement = (ParsedStatement<Pojo>)mock(ParsedStatement.class);
-        when(statement.getParsedStatement()).thenReturn(mockParsedStatement);
-        @SuppressWarnings("unchecked")
-        DataModifyingStatement<Pojo> mockDms = (DataModifyingStatement<Pojo>)mock(DataModifyingStatement.class);
-        @SuppressWarnings("unchecked")
-        Query<Pojo> mockQuery = (Query<Pojo>)mock(Query.class);
-        // First return a write then a query
-        when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockDms).thenReturn(mockQuery);
-        
-        
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(TEST_CATEGORY, "QUERY foo-table");
-        PreparedStatement<FooPojo> decorated = queuedStorage.prepareStatement(desc);
-        assertNotNull(decorated);
-        assertTrue(decorated instanceof QueuedPreparedStatement);
-        assertNotSame(decorated, statement);
-        assertNull(executor.getTask());
-        
-        // make sure execution queues a runnable
-        decorated.execute();
-        assertNotNull(executor.getTask());
-        // reset
-        executor.execute(null);
-        assertNull(executor.getTask());
-        decorated.executeQuery();
-        assertNull("queries are not queued", executor.getTask());
-        
-        QueuedPreparedStatement<FooPojo> stmt = (QueuedPreparedStatement<FooPojo>)decorated;
-        ParsedStatement<FooPojo> parsed = stmt.getParsedStatement();
-        assertNotNull(parsed);
-        // Be sure that getParsedStatement returns simple (non-queued version).
-        // If true, we'd be queueing things twice: via execute() then via
-        // getParsedStatement().
-        assertFalse("Do not want parsed statement decoration for web", parsed instanceof QueuedParsedStatement);
-        Statement<FooPojo> patched = parsed.patchStatement(new PreparedParameter[]{});
-        assertFalse("Do not want parsed statement decoration for web", patched instanceof QueuedWrite);
-        assertNull(executor.getTask());
-        assertTrue(patched instanceof DataModifyingStatement);
-        DataModifyingStatement<FooPojo> write = (DataModifyingStatement<FooPojo>)patched;
-        write.apply();
-        assertNull(executor.getTask());
-        verify(mockDms).apply();
-        verifyNoMoreInteractions(mockDms);
-        // reset
-        executor.execute(null);
-        
-        // now do it again with a query
-        patched = parsed.patchStatement(new PreparedParameter[]{});
-        assertTrue(patched instanceof Query);
-        Query<FooPojo> query = (Query<FooPojo>)patched;
-        assertNull(executor.getTask());
-        assertSame("Didn't expect query to get decorated", mockQuery, query);
-        query.execute();
-        assertNull("should not have submited to executor", executor.getTask());
-        verify(mockQuery).execute();
-        verifyNoMoreInteractions(mockQuery);
-    }
-    
-    /*
-     * QueuedStorage decorates PreparedStatement, which may throw a
-     * StatementExecution exception on stmt.execute(). All the decorator can do
-     * is to log the exception and continue. As such, the decorated
-     * PreparedStatement should never throw that exception. It can't since it
-     * solely submits a runnable for execution.
-     */
-    @Test
-    public void testExecutePreparedStatementFails()
-            throws DescriptorParsingException, StatementExecutionException {
-        assertFalse(delegateStorage instanceof SecureStorage);
-        delegateStorage = mock(SecureStorage.class);
-        queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor);
-        assertFalse(Boolean.getBoolean(Constants.IS_PROXIED_STORAGE));
-        
-        assertTrue("Precondition secure storage FAILED!", delegateStorage instanceof SecureStorage);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<Pojo> statement = (PreparedStatement<Pojo>)mock(PreparedStatement.class);
-        
-        // make sure the delegate throws a StatementExecutionException
-        Mockito.doThrow(StatementExecutionException.class).when(statement).execute();
-        when(delegateStorage.prepareStatement(anyStatementDescriptor())).thenReturn(statement);
-        
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(TEST_CATEGORY, "QUERY foo-table");
-        PreparedStatement<FooPojo> decorated = queuedStorage.prepareStatement(desc);
-        assertNotNull(decorated);
-        assertTrue(decorated instanceof QueuedPreparedStatement);
-        assertNotSame(decorated, statement);
-        assertNull(executor.getTask());
-        
-        // this should not throw the exception the decoratee throws.
-        try {
-            decorated.execute();
-            // pass
-        } catch (StatementExecutionException e) {
-            fail("decorator should only submit task and continue");
-        }
-        assertNotNull(executor.getTask());
-        try {
-            executor.getTask().run();
-            // pass
-        } catch (Exception e) {
-            fail("delegate's StatementExecutionException should have been caught");
-        }
-    }
-    
-    @Test
-    public void testPrepareStatementDescriptorParseFailure() throws DescriptorParsingException, StatementExecutionException {
-        
-        Mockito.doThrow(DescriptorParsingException.class).when(delegateStorage).prepareStatement(anyStatementDescriptor());
-        
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(TEST_CATEGORY, "QUERY foo-table");
-        
-        try {
-            queuedStorage.prepareStatement(desc);
-            fail("should have thrown descptor parsing exception!");
-        } catch (DescriptorParsingException e) {
-            // pass
-        }
-    }
-    
-    @SuppressWarnings("unchecked")
-    private <T extends Pojo> StatementDescriptor<T> anyStatementDescriptor() {
-        return any(StatementDescriptor.class);
-    }
-
-    @Test
-    public void testRegisterCategory() {
-
-        Category<?> category = mock(Category.class);
-
-        queuedStorage.registerCategory(category);
-
-        verify(delegateStorage).registerCategory(category);
-
-        assertNull(executor.getTask());
-        assertNull(fileExecutor.getTask());
-    }
-
-    @Test
-    public void testGetConnection() {
-        Connection connection = mock(Connection.class);
-        when(delegateStorage.getConnection()).thenReturn(connection);
-
-        Connection conn = queuedStorage.getConnection();
-
-        verify(delegateStorage).getConnection();
-
-        assertSame(conn, connection);
-
-        assertNull(executor.getTask());
-        assertNull(fileExecutor.getTask());
-    }
-    
-    @Test
-    public void testShutdown() {
-        queuedStorage.shutdown();
-        verify(delegateStorage).shutdown();
-        assertTrue(executor.isShutdown());
-        assertEquals(3, executor.getAwaitTerminationTimeout());
-        assertEquals(TimeUnit.SECONDS, executor.getAwaitTerminationTimeUnit());
-        assertTrue(fileExecutor.isShutdown());
-        assertEquals(3, fileExecutor.getAwaitTerminationTimeout());
-        assertEquals(TimeUnit.SECONDS, fileExecutor.getAwaitTerminationTimeUnit());
-    }
-    
-    @Test
-    public void executorsShutdownBeforeDelegate() {
-        StubStorage delegate = new StubStorage();
-        TestShutdownExecutor executor = new TestShutdownExecutor();
-        TestShutdownExecutor fileExecutor = new TestShutdownExecutor();
-        queuedStorage = new QueuedStorage(delegate, executor, fileExecutor);
-        queuedStorage.shutdown();
-        
-        // all shutdown methods should have been called
-        assertTrue(-1 != delegate.shutDownTime);
-        assertTrue(-1 != executor.executorShutDownTime);
-        assertTrue(-1 != fileExecutor.executorShutDownTime);
-        // delegate should have shut down last
-        assertTrue(delegate.shutDownTime > executor.executorShutDownTime);
-        assertTrue(delegate.shutDownTime > fileExecutor.executorShutDownTime);
-    }
-    
-    private static class StubStorage implements Storage {
-
-        long shutDownTime = -1;
-
-        @Override
-        public void registerCategory(Category<?> category) {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public Connection getConnection() {
-            // not implemented
-            throw new AssertionError();
-        }        
-
-        @Override
-        public void purge(String agentId) {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public void saveFile(String filename, InputStream data, SaveFileListener listener) {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public InputStream loadFile(String filename) {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public void shutdown() {
-            shutDownTime = System.currentTimeMillis();
-            // delay shutdown just a little
-            try {
-                Thread.sleep(10);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            }
-        }
-
-        @Override
-        public <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc)
-                throws DescriptorParsingException {
-            // not implemented
-            return null;
-        }
-        
-    }
-    
-    private static class FooPojo implements Pojo {
-       // Dummy class for testing 
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/StatementDescriptorTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.AgentInformation;
-import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class StatementDescriptorTest {
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void testToString() {
-        String desc = "QUERY agent-config WHERE 'agentId' = ?s";
-        Category cat = mock(Category.class);
-        StatementDescriptor stmtDesc = new StatementDescriptor(cat, desc);
-        // toString is used extensively for logging.
-        assertEquals(desc, stmtDesc.toString());
-    }
-    
-    @Test
-    public void testHashCode() {
-        String strDesc = "QUERY agent-config";
-        StatementDescriptor<AgentInformation> desc1 = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(AgentInfoDAO.CATEGORY);
-        Category<AggregateCount> aggregateCat = adapter.getAdapted(AggregateCount.class);
-        StatementDescriptor<AggregateCount> desc2 = new StatementDescriptor<>(aggregateCat, strDesc);
-        assertTrue("regular and aggregate category should have different hashcode",
-                desc1.hashCode() != desc2.hashCode());
-        
-        System.out.println("desc1 = " + desc1.hashCode());
-        assertEquals("same descriptors should have same hash code", desc1.hashCode(), desc1.hashCode());
-        assertEquals("same descriptors should have same hash code", desc2.hashCode(), desc2.hashCode());
-        StatementDescriptor<AgentInformation> desc1Dupl = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        assertEquals("same descriptors should have same hash code", desc1.hashCode(), desc1Dupl.hashCode());
-        
-        strDesc = "QUERY " + VmInfoDAO.vmInfoCategory.getName();
-        StatementDescriptor<VmInfo> desc3 = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, strDesc);
-        assertTrue("*very* different descriptors should have different hash code",
-                desc1.hashCode() != desc3.hashCode());
-        
-        strDesc = "QUERY " + VmInfoDAO.vmInfoCategory.getName() + " WHERE 'a' = ?s";
-        StatementDescriptor<VmInfo> desc4 = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, strDesc);
-        assertTrue("different descriptors, but same category should have different hash code",
-                desc3.hashCode() != desc4.hashCode());
-        
-        strDesc = "QUERY agent-config";
-        // doesn't really make sense (would not parse), but this is a hash code test
-        StatementDescriptor<VmInfo> desc5 = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, strDesc);
-        assertTrue("same string desc, but different category should be different hash code",
-                desc5.hashCode() != desc4.hashCode());
-    }
-    
-    @Test
-    public void testEquals() {
-        String strDesc = "QUERY agent-config";
-        StatementDescriptor<AgentInformation> desc1 = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(AgentInfoDAO.CATEGORY);
-        Category<AggregateCount> aggregateCat = adapter.getAdapted(AggregateCount.class);
-        StatementDescriptor<AggregateCount> desc2 = new StatementDescriptor<>(aggregateCat, strDesc);
-        assertFalse("regular and aggregate category should not be equal",
-                desc1.equals(desc2));
-        assertFalse("null not equal non-null desc", desc1.equals(null));
-        assertTrue("self-equals test", desc1.equals(desc1));
-        
-        assertEquals("same descriptors should be equal", desc1, desc1);
-        assertEquals("same descriptors should be equal", desc2, desc2);
-        StatementDescriptor<AgentInformation> desc1Dupl = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        assertEquals("same descriptors should be equal", desc1, desc1Dupl);
-        
-        strDesc = "QUERY " + VmInfoDAO.vmInfoCategory.getName();
-        StatementDescriptor<VmInfo> desc3 = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, strDesc);
-        assertFalse("*very* different descriptors should not be equal",
-                desc1.equals(desc3));
-        
-        strDesc = "QUERY " + VmInfoDAO.vmInfoCategory.getName() + " WHERE 'a' = ?s";
-        StatementDescriptor<VmInfo> desc4 = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, strDesc);
-        assertFalse("different descriptors, but same category should not be equal",
-                desc3.equals(desc4));
-        
-        strDesc = "QUERY agent-config";
-        // doesn't really make sense (would not parse), but will do for this test
-        StatementDescriptor<VmInfo> desc5 = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, strDesc);
-        assertFalse("same string desc, but different category should not be equal",
-                desc5.equals(desc4));
-    }
-    
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetterTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-public class VmBoundaryPojoGetterTest {
-    private static final String AGENT_ID = "agentid";
-    private static final String HOSTNAME = "host.example.com";
-    private static final String VM_ID = "vmId";
-    private static final int VM_PID = 123;
-    private static final String MAIN_CLASS = "Foo.class";
-    private static final String CATEGORY_NAME = "vm-boundary-category";
-    // Make this one static so we don't get IllegalStateException from trying
-    // to make category of same name while running tests in same classloader.
-    private static final Category<TestPojo> cat = new Category<>(CATEGORY_NAME, TestPojo.class);
-
-    private static long t1 = 1;
-    private static long t2 = 5;
-
-    private static long lc1 = 10;
-    private static long lc2 = 20;
-
-    private HostRef hostRef;
-    private VmRef vmRef;
-    private AgentId agentId;
-    private VmId vmId;
-    private TestPojo result1, result2;
-
-    @Before
-    public void setUp() {
-        hostRef = new HostRef(AGENT_ID, HOSTNAME);
-        vmRef = new VmRef(hostRef, VM_ID, VM_PID, MAIN_CLASS);
-        agentId = new AgentId(AGENT_ID);
-        vmId = new VmId(VM_ID);
-        result1 = mock(TestPojo.class);
-        when(result1.getTimeStamp()).thenReturn(t1);
-        when(result1.getData()).thenReturn(lc1);
-        result2 = mock(TestPojo.class);
-        when(result2.getTimeStamp()).thenReturn(t2);
-        when(result2.getData()).thenReturn(lc2);
-    }
-
-    @Test
-    public void verifyLatestQueryDescriptorFormat() {
-        String newestExpected = "QUERY %s WHERE 'agentId' = ?s AND " +
-                "'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
-        assertEquals(newestExpected, VmBoundaryPojoGetter.DESC_NEWEST_VM_STAT);
-    }
-
-    @Test
-    public void verifyOldestQueryDescriptorFormat() {
-        String oldestExpected = "QUERY %s WHERE 'agentId' = ?s AND " +
-                "'vmId' = ?s SORT 'timeStamp' ASC LIMIT 1";
-        assertEquals(oldestExpected, VmBoundaryPojoGetter.DESC_OLDEST_VM_STAT);
-    }
-
-    @Test
-    public void verifyLatestQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        VmBoundaryPojoGetter<TestPojo> getter = new VmBoundaryPojoGetter<>(storage, cat);
-
-        String actualLatestDesc = getter.getNewestQueryDesc();
-        String newestExpected = "QUERY vm-boundary-category WHERE 'agentId' = ?s AND " +
-                "'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
-        assertEquals(newestExpected, actualLatestDesc);
-    }
-
-    @Test
-    public void verifyOldestQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        VmBoundaryPojoGetter<TestPojo> getter = new VmBoundaryPojoGetter<>(storage, cat);
-
-        String actualOldestDesc = getter.getOldestQueryDesc();
-        String oldestExpected = "QUERY vm-boundary-category WHERE 'agentId' = ?s AND " +
-                "'vmId' = ?s SORT 'timeStamp' ASC LIMIT 1";
-
-        assertEquals(oldestExpected, actualOldestDesc);
-    }
-
-    @Test
-    public void testVmRefGetOldest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        VmBoundaryPojoGetter<TestPojo> getter = new VmBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo oldest = getter.getOldestStat(vmRef);
-
-        assertEquals(t1, oldest.getTimeStamp());
-        assertEquals(lc1, oldest.getData());
-    }
-
-    @Test
-    public void testGetOldest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        VmBoundaryPojoGetter<TestPojo> getter = new VmBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo oldest = getter.getOldestStat(vmId, agentId);
-
-        assertEquals(t1, oldest.getTimeStamp());
-        assertEquals(lc1, oldest.getData());
-    }
-
-    @Test
-    public void testVmRefGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result2).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        VmBoundaryPojoGetter<TestPojo> getter = new VmBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo newest = getter.getNewestStat(vmRef);
-
-        assertEquals(t2, newest.getTimeStamp());
-        assertEquals(lc2, newest.getData());
-    }
-
-    @Test
-    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result2).thenReturn(null);
-
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-
-        VmBoundaryPojoGetter<TestPojo> getter = new VmBoundaryPojoGetter<>(storage, cat);
-
-        TestPojo newest = getter.getNewestStat(vmId, agentId);
-
-        assertEquals(t2, newest.getTimeStamp());
-        assertEquals(lc2, newest.getData());
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<TestPojo> anyDescriptor() {
-        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
-    }
-
-    private static interface TestPojo extends TimeStampedPojo {
-        long getData();
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.junit.Assert.assertNotNull;
-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;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.Pair;
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-public class VmLatestPojoListGetterTest {
-    private static final String AGENT_ID = "agentid";
-    private static final String HOSTNAME = "host.example.com";
-    private static final String VM_ID = "vmId";
-    private static final int VM_PID = 123;
-    private static final String MAIN_CLASS = "Foo.class";
-    private static final String CATEGORY_NAME = "vmcategory";
-    // Make this one static so we don't get IllegalStateException from trying
-    // to make category of same name while running tests in same classloader.
-    private static final Category<TestPojo> cat =  new Category<>(CATEGORY_NAME, TestPojo.class);
-
-    private static long t1 = 1;
-    private static long t2 = 5;
-    private static long t3 = 10;
-
-    private static long lc1 = 10;
-    private static long lc2 = 20;
-    private static long lc3 = 30;
-
-    private HostRef hostRef;
-    private VmRef vmRef;
-    private AgentId agentId;
-    private VmId vmId;
-    private TestPojo result1, result2, result3;
-
-    @Before
-    public void setUp() {
-        hostRef = new HostRef(AGENT_ID, HOSTNAME);
-        vmRef = new VmRef(hostRef, VM_ID, VM_PID, MAIN_CLASS);
-        agentId = new AgentId(AGENT_ID);
-        vmId = new VmId(VM_ID);
-        result1 = mock(TestPojo.class);
-        when(result1.getTimeStamp()).thenReturn(t1);
-        when(result1.getData()).thenReturn(lc1);
-        result2 = mock(TestPojo.class);
-        when(result2.getTimeStamp()).thenReturn(t2);
-        when(result2.getData()).thenReturn(lc2);
-        result3 = mock(TestPojo.class);
-        when(result3.getTimeStamp()).thenReturn(t3);
-        when(result3.getData()).thenReturn(lc3);
-    }
-    
-    @Test
-    public void verifyQueryDescriptorFormat() {
-        String expected = "QUERY %s WHERE 'agentId' = ?s AND " +
-         "'vmId' = ?s AND 'timeStamp' > ?l SORT 'timeStamp' DSC";
-        assertEquals(expected, VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT);
-    }
-    
-    @Test
-    public void verifyQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
-        String actualDesc = getter.getQueryLatestDesc();
-        String expected = "QUERY vmcategory WHERE 'agentId' = ?s AND " +
-         "'vmId' = ?s AND 'timeStamp' > ?l SORT 'timeStamp' DSC";
-        assertEquals(expected, actualDesc);
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<TestPojo> anyDescriptor() {
-        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
-    }
-
-    @Test
-    public void testVmRefGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        Pair<Storage, PreparedStatement<TestPojo>> setup = setupGetLatest();
-        Storage storage = setup.getFirst();
-        PreparedStatement<TestPojo> query = setup.getSecond();
-
-        VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
-        List<TestPojo> stats = getter.getLatest(vmRef, t2);
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(query).setString(0, AGENT_ID);
-        verify(query).setString(1, VM_ID);
-        verify(query).setLong(2, t2);
-        verify(query).executeQuery();
-        verifyNoMoreInteractions(query);
-
-        assertNotNull(stats);
-        assertEquals(2, stats.size());
-        TestPojo stat1 = stats.get(0);
-        assertEquals(t1, stat1.getTimeStamp());
-        assertEquals(lc1, stat1.getData());
-        TestPojo stat2 = stats.get(1);
-        assertEquals(t2, stat2.getTimeStamp());
-        assertEquals(lc2, stat2.getData());
-    }
-
-    @Test
-    public void testGetLatest() throws DescriptorParsingException, StatementExecutionException {
-        Pair<Storage, PreparedStatement<TestPojo>> setup = setupGetLatest();
-        Storage storage = setup.getFirst();
-        PreparedStatement<TestPojo> query = setup.getSecond();
-
-        VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
-        List<TestPojo> stats = getter.getLatest(agentId, vmId, t2);
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(query).setString(0, AGENT_ID);
-        verify(query).setString(1, VM_ID);
-        verify(query).setLong(2, t2);
-        verify(query).executeQuery();
-        verifyNoMoreInteractions(query);
-
-        assertNotNull(stats);
-        assertEquals(2, stats.size());
-        TestPojo stat1 = stats.get(0);
-        assertEquals(t1, stat1.getTimeStamp());
-        assertEquals(lc1, stat1.getData());
-        TestPojo stat2 = stats.get(1);
-        assertEquals(t2, stat2.getTimeStamp());
-        assertEquals(lc2, stat2.getData());
-    }
-
-    private Pair<Storage, PreparedStatement<TestPojo>> setupGetLatest() throws
-            DescriptorParsingException, StatementExecutionException {
-
-        @SuppressWarnings("unchecked")
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        return new Pair<>(storage, query);
-    }
-    
-    private static interface TestPojo extends TimeStampedPojo {
-        
-        long getData();
-        
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetterTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/*
- * Copyright 2012-2017 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.assertEquals;
-import static org.junit.Assert.assertNotNull;
-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;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.model.TimeStampedPojo;
-
-public class VmTimeIntervalPojoListGetterTest {
-    private static final String AGENT_ID = "agentid";
-    private static final String HOSTNAME = "host.example.com";
-    private static final String VM_ID = "vmId";
-    private static final int VM_PID = 123;
-    private static final String MAIN_CLASS = "Foo.class";
-    private static final String CATEGORY_NAME = "vm-timeinterval-category";
-    // Make this one static so we don't get IllegalStateException from trying
-    // to make category of same name while running tests in same classloader.
-    private static final Category<TestPojo> cat = new Category<>(CATEGORY_NAME, TestPojo.class);
-
-    private static long t1 = 1;
-    private static long t2 = 5;
-    private static long t3 = 10;
-
-    private static long lc1 = 10;
-    private static long lc2 = 20;
-    private static long lc3 = 30;
-
-    private HostRef hostRef;
-    private VmRef vmRef;
-    private AgentId agentId;
-    private VmId vmId;
-    private TestPojo result1, result2, result3;
-
-    @Before
-    public void setUp() {
-        hostRef = new HostRef(AGENT_ID, HOSTNAME);
-        vmRef = new VmRef(hostRef, VM_ID, VM_PID, MAIN_CLASS);
-        agentId = new AgentId(AGENT_ID);
-        vmId = new VmId(VM_ID);
-        result1 = mock(TestPojo.class);
-        when(result1.getTimeStamp()).thenReturn(t1);
-        when(result1.getData()).thenReturn(lc1);
-        result2 = mock(TestPojo.class);
-        when(result2.getTimeStamp()).thenReturn(t2);
-        when(result2.getData()).thenReturn(lc2);
-        result3 = mock(TestPojo.class);
-        when(result3.getTimeStamp()).thenReturn(t3);
-        when(result3.getData()).thenReturn(lc3);
-    }
-
-    @Test
-    public void verifyQueryDescriptorFormat() {
-        String expected = "QUERY %s WHERE 'agentId' = ?s AND " +
-                "'vmId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' < ?l SORT 'timeStamp' DSC";
-        assertEquals(expected, VmTimeIntervalPojoListGetter.VM_INTERVAL_QUERY_FORMAT);
-    }
-
-    @Test
-    public void verifyQueryDescriptorIsSane() {
-        Storage storage = mock(Storage.class);
-        VmTimeIntervalPojoListGetter<TestPojo> getter = new VmTimeIntervalPojoListGetter<>(storage, cat);
-        String actualDesc = getter.getQueryLatestDesc();
-        String expected = "QUERY " + CATEGORY_NAME + " WHERE 'agentId' = ?s AND " +
-                "'vmId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' < ?l SORT 'timeStamp' DSC";
-        assertEquals(expected, actualDesc);
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<TestPojo> anyDescriptor() {
-        return (StatementDescriptor<TestPojo>) any(StatementDescriptor.class);
-    }
-
-    @Test
-    public void testVmRefGetInterval() throws DescriptorParsingException, StatementExecutionException {
-        @SuppressWarnings("unchecked")
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        VmTimeIntervalPojoListGetter<TestPojo> getter = new VmTimeIntervalPojoListGetter<>(storage, cat);
-
-        List<TestPojo> stats = getter.getLatest(vmRef, t1, t2);
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(query).setString(0, AGENT_ID);
-        verify(query).setString(1, VM_ID);
-        verify(query).setLong(2, t1);
-        verify(query).setLong(3, t2);
-        verify(query).executeQuery();
-        verifyNoMoreInteractions(query);
-
-        assertNotNull(stats);
-        assertEquals(2, stats.size());
-        TestPojo stat1 = stats.get(0);
-        assertEquals(t1, stat1.getTimeStamp());
-        assertEquals(lc1, stat1.getData());
-        TestPojo stat2 = stats.get(1);
-        assertEquals(t2, stat2.getTimeStamp());
-        assertEquals(lc2, stat2.getData());
-    }
-
-    @Test
-    public void testGetInterval() throws DescriptorParsingException, StatementExecutionException {
-        @SuppressWarnings("unchecked")
-        Cursor<TestPojo> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> query = (PreparedStatement<TestPojo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(query);
-        when(query.executeQuery()).thenReturn(cursor);
-
-        VmTimeIntervalPojoListGetter<TestPojo> getter = new VmTimeIntervalPojoListGetter<>(storage, cat);
-
-        List<TestPojo> stats = getter.getLatest(agentId, vmId, t1, t2);
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(query).setString(0, AGENT_ID);
-        verify(query).setString(1, VM_ID);
-        verify(query).setLong(2, t1);
-        verify(query).setLong(3, t2);
-        verify(query).executeQuery();
-        verifyNoMoreInteractions(query);
-
-        assertNotNull(stats);
-        assertEquals(2, stats.size());
-        TestPojo stat1 = stats.get(0);
-        assertEquals(t1, stat1.getTimeStamp());
-        assertEquals(lc1, stat1.getData());
-        TestPojo stat2 = stats.get(1);
-        assertEquals(t2, stat2.getTimeStamp());
-        assertEquals(lc2, stat2.getData());
-    }
-
-    private static interface TestPojo extends TimeStampedPojo {
-        long getData();
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoOperationResultTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class AbstractDaoOperationResultTest {
-
-    @Test
-    public void testHasExceptions() {
-        AbstractDaoOperationResult<VmInfo> abstractDaoOperationResult = getAbstractDaoOperationResult();
-        assertFalse(abstractDaoOperationResult.hasExceptions());
-        Exception e = new Exception();
-        abstractDaoOperationResult.addException(e);
-        assertTrue(abstractDaoOperationResult.hasExceptions());
-    }
-
-    @Test
-    public void testAddException() {
-        AbstractDaoOperationResult<VmInfo> abstractDaoOperationResult = getAbstractDaoOperationResult();
-        Exception e1 = new Exception();
-        abstractDaoOperationResult.addException(e1);
-        assertFalse(abstractDaoOperationResult.getExceptions().isEmpty());
-        assertThat(abstractDaoOperationResult.getExceptions(), is(equalTo(Collections.singletonList(e1))));
-    }
-
-    @Test
-    public void testAddExceptions() {
-        AbstractDaoOperationResult<VmInfo> abstractDaoOperationResult = getAbstractDaoOperationResult();
-        Exception e1 = new Exception("foo");
-        Exception e2 = new Exception("bar");
-        List<Exception> exceptions = new ArrayList<>();
-        exceptions.add(e1);
-        exceptions.add(e2);
-        abstractDaoOperationResult.addExceptions(exceptions);
-        assertFalse(abstractDaoOperationResult.getExceptions().isEmpty());
-        assertThat(abstractDaoOperationResult.getExceptions(), is(equalTo(exceptions)));
-    }
-
-    @Test
-    public void testAddExceptionsIsDefensive() {
-        // test that addExceptions makes a defensive copy, so that client code which bulk adds exceptions
-        // is not able to add further exceptions to the AbstractDaoOperationResult by simply adding exceptions
-        // to its own reference to the exceptions collection, rather than having to call through addException
-        // or addExceptions again
-        AbstractDaoOperationResult<VmInfo> abstractDaoOperationResult = getAbstractDaoOperationResult();
-        Exception e1 = new Exception("foo");
-        Exception e2 = new Exception("bar");
-        List<Exception> exceptions = new ArrayList<>();
-        exceptions.add(e1);
-        exceptions.add(e2);
-        abstractDaoOperationResult.addExceptions(exceptions);
-        assertFalse(abstractDaoOperationResult.getExceptions().isEmpty());
-        assertThat(abstractDaoOperationResult.getExceptions(), is(equalTo(exceptions)));
-        Exception e3 = new Exception("baz");
-        exceptions.add(e3);
-        assertFalse(abstractDaoOperationResult.getExceptions().contains(e3));
-    }
-
-    @Test
-    public void testGetExceptions() {
-        AbstractDaoOperationResult<VmInfo> abstractDaoOperationResult = getAbstractDaoOperationResult();
-        Exception e1 = new Exception("foo");
-        Exception e2 = new Exception("bar");
-        Collection<Exception> exceptions = new HashSet<>();
-        exceptions.add(e1);
-        exceptions.add(e2);
-        abstractDaoOperationResult.addExceptions(exceptions);
-        assertFalse(abstractDaoOperationResult.getExceptions().isEmpty());
-        assertEquals(exceptions.size(), abstractDaoOperationResult.getExceptions().size());
-        for (Exception e : exceptions) {
-            assertTrue(abstractDaoOperationResult.getExceptions().contains(e));
-        }
-    }
-
-    @Test(expected = UnsupportedOperationException.class)
-    public void testGetExceptionsImmutable() {
-        getAbstractDaoOperationResult().getExceptions().add(new Exception());
-    }
-
-    private AbstractDaoOperationResult<VmInfo> getAbstractDaoOperationResult() {
-        return new AbstractDaoOperationResult<VmInfo>() {
-            @Override
-            public Iterator<VmInfo> iterator() {
-                VmInfo vmInfo1 = mock(VmInfo.class);
-                VmInfo vmInfo2 = mock(VmInfo.class);
-                return Arrays.asList(vmInfo1, vmInfo2).iterator();
-            }
-        };
-    }
-
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoOperationTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AbstractDaoOperation;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class AbstractDaoOperationTest {
-
-    private Storage storage;
-    private Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-    private String descriptor = "descriptor";
-
-    @Before
-    public void setup() {
-        storage = mock(Storage.class);
-    }
-
-    @Test
-    public void testGetStorage() {
-        AbstractDaoOperation<VmInfo> abstractDaoOperation = getAbstractDaoOperation();
-        Storage s = abstractDaoOperation.getStorage();
-        assertThat(s, is(storage));
-    }
-
-    @Test
-    public void testGetStatementDescriptor() {
-        AbstractDaoOperation<VmInfo> abstractDaoOperation = getAbstractDaoOperation();
-        StatementDescriptor<VmInfo> statementDescriptor = abstractDaoOperation.getStatementDescriptor();
-        StatementDescriptor<VmInfo> expected = new StatementDescriptor<>(category, descriptor);
-        assertThat(statementDescriptor, is(equalTo(expected)));
-    }
-
-    private AbstractDaoOperation<VmInfo> getAbstractDaoOperation() {
-        return new AbstractDaoOperation<VmInfo>(storage, category, descriptor) {
-            @Override
-            public PreparedStatement<VmInfo> customize(PreparedStatement<VmInfo> preparedStatement) {
-                return preparedStatement;
-            }
-        };
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoQueryTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class AbstractDaoQueryTest {
-
-    @Test @SuppressWarnings("unchecked")
-    public void testExecute() throws StatementExecutionException, DescriptorParsingException {
-        PreparedStatement<VmInfo> preparedStatement = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        Storage storage = mock(Storage.class);
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        Cursor<VmInfo> cursor = (Cursor<VmInfo>) mock(Cursor.class);
-        when(preparedStatement.executeQuery()).thenReturn(cursor);
-        AbstractDaoQuery<VmInfo> abstractDaoQuery = new AbstractDaoQuery<VmInfo>(storage, category, descriptor) {
-            @Override
-            public PreparedStatement<VmInfo> customize(PreparedStatement<VmInfo> preparedStatement) {
-                return preparedStatement;
-            }
-        };
-        Cursor<VmInfo> c = abstractDaoQuery.execute(preparedStatement);
-        assertThat(c, is(cursor));
-        verify(preparedStatement).executeQuery();
-        verify(preparedStatement, never()).execute();
-    }
-}
\ No newline at end of file
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoStatementTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class AbstractDaoStatementTest {
-
-    @Test
-    @SuppressWarnings("unchecked")
-    public void testExecute() throws StatementExecutionException, DescriptorParsingException {
-        PreparedStatement<VmInfo> preparedStatement = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        Storage storage = mock(Storage.class);
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        Cursor<VmInfo> cursor = (Cursor<VmInfo>) mock(Cursor.class);
-        when(preparedStatement.executeQuery()).thenReturn(cursor);
-        DaoStatement<VmInfo> abstractDaoQuery = new SimpleDaoStatement<>(storage, category, descriptor);
-        abstractDaoQuery.execute(preparedStatement);
-        verify(preparedStatement).execute();
-        verify(preparedStatement, never()).executeQuery();
-    }
-
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/AbstractDaoTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.logging.Logger;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class AbstractDaoTest {
-
-    private static final List<VmInfo> MOCK_RESULTS = Arrays.asList(mock(VmInfo.class), mock(VmInfo.class));
-
-    @Test
-    public void testGetEmptyResultCursor() {
-        Cursor<VmInfo> cursor = AbstractDao.getEmptyResultCursor();
-        assertThat(cursor.hasNext(), is(false));
-        assertThat(cursor.next(), is(equalTo(null)));
-        assertThat(cursor.getBatchSize(), is(0));
-    }
-
-    @Test
-    public void testGetCustomizedPreparedStatement() throws DescriptorParsingException {
-        Storage storage = mock(Storage.class);
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        @SuppressWarnings("unchecked")
-        final PreparedStatement<VmInfo> DUMMY_STATEMENT = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        DaoOperation<VmInfo> daoOperation = new AbstractDaoStatement<VmInfo>(storage, category, descriptor) {
-            @Override
-            public PreparedStatement<VmInfo> customize(PreparedStatement<VmInfo> preparedStatement) {
-                return DUMMY_STATEMENT;
-            }
-        };
-        AbstractDao abstractDao = getAbstractDao();
-
-        assertThat(abstractDao.getCustomizedPreparedStatement(daoOperation), is(equalTo(DUMMY_STATEMENT)));
-    }
-
-    @Test @SuppressWarnings("unchecked")
-    public void testExecuteStatement() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        PreparedStatement<VmInfo> statement = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(statement);
-        Cursor<VmInfo> sentinelCursor = getSentinelCursor();
-        when(statement.executeQuery()).thenReturn(sentinelCursor);
-
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        DaoStatement<VmInfo> daoOperation = new SimpleDaoStatement<>(storage, category, descriptor);
-        AbstractDao abstractDao = getAbstractDao();
-        StatementResult<VmInfo> statementResult = abstractDao.executeStatement(daoOperation);
-        assertThat(statementResult.hasExceptions(), is(false));
-    }
-
-    @Test @SuppressWarnings("unchecked")
-    public void testExecuteQuery() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        PreparedStatement<VmInfo> statement = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(statement);
-        Cursor<VmInfo> sentinelCursor = getSentinelCursor();
-        when(statement.executeQuery()).thenReturn(sentinelCursor);
-
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        DaoQuery<VmInfo> daoOperation = new SimpleDaoQuery<>(storage, category, descriptor);
-        AbstractDao abstractDao = getAbstractDao();
-        QueryResult<VmInfo> queryResult = abstractDao.executeQuery(daoOperation);
-        assertThat(queryResult.hasExceptions(), is(false));
-        assertEquals(MOCK_RESULTS, queryResult.asList());
-    }
-
-    private Cursor<VmInfo> getSentinelCursor() {
-        return new Cursor<VmInfo>() {
-
-            private final Iterator<VmInfo> iterator = MOCK_RESULTS.iterator();
-
-            @Override
-            public void setBatchSize(int n) throws IllegalArgumentException {
-            }
-
-            @Override
-            public int getBatchSize() {
-                return 0;
-            }
-
-            @Override
-            public boolean hasNext() {
-                return iterator.hasNext();
-            }
-
-            @Override
-            public VmInfo next() {
-                return iterator.next();
-            }
-
-            @Override
-            public void remove() {
-                throw new UnsupportedOperationException();
-            }
-        };
-    }
-
-    private AbstractDao getAbstractDao() {
-        return new AbstractDao() {
-            @Override
-            protected Logger getLogger() {
-                return LoggingUtils.getLogger(AbstractDaoTest.this.getClass());
-            }
-        };
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<VmInfo> anyDescriptor() {
-        return (StatementDescriptor<VmInfo>) any(StatementDescriptor.class);
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/BaseCountableTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.AggregateCount;
-
-public class BaseCountableTest {
-
-    @Test
-    public void testGetCountSuccessful() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
-        BaseCountable countable = new BaseCountable();
-        String strDesc = "QUERY-COUNT vm-info";
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<AggregateCount> prepared = (PreparedStatement<AggregateCount>)mock(PreparedStatement.class);
-        when(storage.prepareStatement(eq(desc))).thenReturn(prepared);
-        AggregateCount c = new AggregateCount();
-        c.setCount(3);
-        Cursor<AggregateCount> cursor = c.getCursor();
-        when(prepared.executeQuery()).thenReturn(cursor);
-        long count = countable.getCount(storage, mockCategory, strDesc);
-        assertEquals(3, count);
-    }
-    
-    @Test
-    public void testGetCountError() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
-        BaseCountable countable = new BaseCountable();
-        String strDesc = "QUERY-COUNT vm-info";
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
-        doThrow(DescriptorParsingException.class).when(storage).prepareStatement(eq(desc));
-        long count = countable.getCount(storage, mockCategory, strDesc);
-        assertEquals(-1, count);
-    }
-    
-    @Test
-    public void testGetCountError2() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
-        BaseCountable countable = new BaseCountable();
-        String strDesc = "QUERY-COUNT vm-info";
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<AggregateCount> prepared = (PreparedStatement<AggregateCount>)mock(PreparedStatement.class);
-        when(storage.prepareStatement(eq(desc))).thenReturn(prepared);
-        doThrow(StatementExecutionException.class).when(prepared).executeQuery();
-        long count = countable.getCount(storage, mockCategory, strDesc);
-        assertEquals(-1, count);
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/QueryResultTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class QueryResultTest {
-
-    private static final List<VmInfo> MOCK_RESULTS = Collections.unmodifiableList(Arrays.asList(mock(VmInfo.class), mock(VmInfo.class)));
-
-    @Test
-    public void testAsListContents() {
-        QueryResult<VmInfo> queryResult = getQueryResult(MOCK_RESULTS);
-        List<VmInfo> list = queryResult.asList();
-        assertThat(list, is(equalTo(MOCK_RESULTS)));
-    }
-
-    @Test
-    public void testAsListAllowsInPlaceModification() {
-        QueryResult<VmInfo> queryResult = getQueryResult(MOCK_RESULTS);
-        List<VmInfo> list = queryResult.asList();
-        VmInfo foo = mock(VmInfo.class);
-        list.add(foo);
-        assertThat(queryResult.asList().contains(foo), is(true));
-        list.clear();
-        assertThat(queryResult.asList().isEmpty(), is(true));
-    }
-
-    @Test
-    public void testHeadEmpty() {
-        QueryResult<VmInfo> queryResult = getQueryResult(Collections.<VmInfo>emptyList());
-        VmInfo head = queryResult.head();
-        assertThat(head, is(equalTo(null)));
-    }
-
-    @Test
-    public void testHeadNonEmpty() {
-        QueryResult<VmInfo> queryResult = getQueryResult(MOCK_RESULTS);
-        VmInfo head = queryResult.head();
-        assertThat(head, is(MOCK_RESULTS.get(0)));
-    }
-
-    @Test
-    public void testIterator() {
-        QueryResult<VmInfo> queryResult = getQueryResult(MOCK_RESULTS);
-        Iterator<VmInfo> iterator = queryResult.iterator();
-        List<VmInfo> list = new ArrayList<>();
-        while (iterator.hasNext()) {
-            list.add(iterator.next());
-        }
-        assertThat(list, is(equalTo(MOCK_RESULTS)));
-    }
-
-    @Test
-    public void testIteratorCanRemove() {
-        List<VmInfo> list = new ArrayList<>();
-        list.addAll(MOCK_RESULTS);
-        VmInfo foo = MOCK_RESULTS.get(0);
-        QueryResult<VmInfo> queryResult = getQueryResult(list);
-        assertThat(queryResult.asList().size(), is(equalTo(2)));
-        assertThat(queryResult.asList().contains(foo), is(true));
-        Iterator<VmInfo> iterator = queryResult.iterator();
-        iterator.next();
-        iterator.remove();
-        assertThat(queryResult.asList().size(), is(equalTo(1)));
-        assertThat(queryResult.asList().contains(foo), is(false));
-    }
-
-    private QueryResult<VmInfo> getQueryResult(final List<VmInfo> list) {
-        Cursor<VmInfo> cursor = new Cursor<VmInfo>() {
-
-            private final Iterator<VmInfo> it = list.iterator();
-
-            @Override
-            public void setBatchSize(int n) throws IllegalArgumentException {
-            }
-
-            @Override
-            public int getBatchSize() {
-                return 0;
-            }
-
-            @Override
-            public boolean hasNext() {
-                return it.hasNext();
-            }
-
-            @Override
-            public VmInfo next() {
-                return it.next();
-            }
-
-            @Override
-            public void remove() {
-                throw new UnsupportedOperationException();
-            }
-        };
-        return new QueryResult<>(cursor);
-    }
-
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/SimpleDaoQueryTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.SimpleDaoQuery;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-public class SimpleDaoQueryTest {
-
-    @Test
-    public void testNoCustomizationDone() {
-        Storage storage = mock(Storage.class);
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        SimpleDaoQuery<VmInfo> simpleDaoQuery = new SimpleDaoQuery<>(storage, category, descriptor);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<VmInfo> preparedStatement = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        PreparedStatement<VmInfo> customized = simpleDaoQuery.customize(preparedStatement);
-        assertThat(customized, is(equalTo(preparedStatement)));
-        verifyZeroInteractions(preparedStatement);
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/SimpleDaoStatementTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.SimpleDaoStatement;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-public class SimpleDaoStatementTest {
-
-    @Test
-    public void testNoCustomizationDone() {
-        Storage storage = mock(Storage.class);
-        Category<VmInfo> category = VmInfoDAO.vmInfoCategory;
-        String descriptor = "descriptor";
-        SimpleDaoStatement<VmInfo> simpleDaoStatement = new SimpleDaoStatement<>(storage, category, descriptor);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<VmInfo> preparedStatement = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
-        PreparedStatement<VmInfo> customized = simpleDaoStatement.customize(preparedStatement);
-        assertThat(customized, is(equalTo(preparedStatement)));
-        verifyZeroInteractions(preparedStatement);
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/dao/StatementResultTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright 2012-2017 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.dao;
-
-import com.redhat.thermostat.storage.model.VmInfo;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-public class StatementResultTest {
-
-    @Test
-    public void testIteratorIsEmpty() {
-        StatementResult<VmInfo> statementResult = new StatementResult<>();
-        assertThat(statementResult.iterator().hasNext(), is(false));
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Fri May 19 11:37:45 2017 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Fri May 19 11:58:05 2017 +0200
@@ -47,7 +47,6 @@
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
@@ -103,15 +102,11 @@
     @Test
     public void verifyActivatorRegistersServicesMultipleTimes() throws Exception {
         StubBundleContext context = new StubBundleContext();
-        Storage storage = mock(Storage.class);
-                
         ApplicationService appService = mock(ApplicationService.class);
         TimerFactory timerFactory = mock(TimerFactory.class);
         when(appService.getTimerFactory()).thenReturn(timerFactory);        
         Timer timer = mock(Timer.class);
         when(timerFactory.createTimer()).thenReturn(timer);
-
-        context.registerService(Storage.class, storage, null);
         context.registerService(ApplicationService.class, appService, null);
 
         Activator activator = new Activator();
@@ -127,7 +122,7 @@
         activator.stop(context);
         
         assertEquals(0, context.getServiceListeners().size());
-        assertEquals(2, context.getAllServices().size());
+        assertEquals(1, context.getAllServices().size());
         
         activator.start(context);
 
@@ -140,7 +135,7 @@
         activator.stop(context);
 
         assertEquals(0, context.getServiceListeners().size());
-        assertEquals(2, context.getAllServices().size());
+        assertEquals(1, context.getAllServices().size());
         
     }
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/DbServiceImplTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,506 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.storage.core.Connection;
-import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
-import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
-import com.redhat.thermostat.storage.core.ConnectionException;
-import com.redhat.thermostat.storage.core.DbService;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-import com.redhat.thermostat.storage.core.StorageException;
-import com.redhat.thermostat.storage.core.StorageProvider;
-import com.redhat.thermostat.testutils.StubBundleContext;
-
-public class DbServiceImplTest {
-    
-    // Stub connection which is always successful and
-    // firesChanged immediately.
-    private ImmediateConnection connection = new ImmediateConnection();
-    private StorageProvider storageProvider;
-    private Storage storage;
-    private StubBundleContext context;
-    private StorageCredentials creds;
-    private SSLConfiguration sslConf;
-    
-    @Before
-    public void setup() {
-        context = new StubBundleContext();
-        sslConf = mock(SSLConfiguration.class);
-
-        storage = mock(Storage.class);
-        when(storage.getConnection()).thenReturn(connection);
-
-        storageProvider = mock(StorageProvider.class);
-        when(storageProvider.canHandleProtocol()).thenReturn(true);
-        when(storageProvider.createStorage()).thenReturn(storage);
-        context.registerService(StorageProvider.class, storageProvider, null);
-
-        creds = mock(StorageCredentials.class);
-    }
-
-    @Test
-    public void testNoStorageProvider() {
-        context = new StubBundleContext();
-
-        try {
-            new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-            fail("exception expected");
-        } catch (StorageException se) {
-            assertEquals("No storage provider available", se.getMessage());
-        }
-    }
-
-    @Test
-    public void testNoStorageProviderCanHandleStorageUrl() {
-        when(storageProvider.canHandleProtocol()).thenReturn(false);
-
-        try {
-            new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-            fail("exception expected");
-        } catch (StorageException se) {
-            assertEquals("No storage found for URL http://ignored.example.com", se.getMessage());
-        }
-    }
-
-    @Test
-    public void testConnect() {
-        DbService dbService = new DbServiceImpl(context, storage, creds, sslConf);
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-    }
-    
-    @Test
-    public void connectEnsuresPostConditionOnDelayedException() {
-        Storage mockStorage = mock(Storage.class);
-        DelayedConnection connection = new DelayedConnection();
-        when(mockStorage.getConnection()).thenReturn(connection);
-        DbService dbService = new DbServiceImpl(context, mockStorage, creds, sslConf);
-        
-        try {
-            dbService.connect();
-            fail("Should have thrown ConnectionException!");
-        } catch (ConnectionException e) {
-            // pass
-        }
-        assertTrue(connection.connectCalled);
-        assertTrue(connection.delayAwaited);
-        assertFalse(context.isServiceRegistered(Storage.class.getName(), mockStorage.getClass()));
-        assertFalse(context.isServiceRegistered(DbService.class.getName(), DbServiceImpl.class));
-    }
-    
-    @Test
-    public void disconnectAwaitsConnectionDisconnect() {
-        Storage mockStorage = mock(Storage.class);
-        DelayedConnection connection = new DelayedConnection() {
-            @Override
-            public void connect() {
-                fireChanged(ConnectionStatus.CONNECTED);
-                connectCalled = true;
-            }
-        };
-        when(mockStorage.getConnection()).thenReturn(connection);
-        DbService dbService = new DbServiceImpl(context, mockStorage, creds, sslConf);
-        
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        connection.connectCalled = false;
-        assertFalse(connection.delayAwaited);
-        assertFalse(connection.disconnectCalled);
-        assertNotNull(context.getServiceReference(DbService.class));
-        assertNotNull(context.getServiceReference(Storage.class));
-        
-        try {
-            dbService.disconnect();
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.disconnectCalled);
-        assertFalse(connection.connectCalled);
-        assertTrue(connection.delayAwaited);
-        assertNull(context.getServiceReference(DbService.class));
-        assertNull(context.getServiceReference(Storage.class));
-    }
-
-    @Test
-    public void testConnectRegistersDbService() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        @SuppressWarnings("rawtypes")
-        ServiceReference dbServiceRef = context.getServiceReference(DbService.class);
-        // connect registers DbService
-        assertNotNull(dbServiceRef);
-        // make sure we really get the same instance
-        assertTrue(dbService.equals(context.getService(dbServiceRef)));
-    }
-    
-    @Test
-    public void testConnectRegistersStorage() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        @SuppressWarnings("rawtypes")
-        ServiceReference storageRef = context.getServiceReference(Storage.class);
-        // connect registers DbService
-        assertNotNull(storageRef);
-        // make sure we really get the same instance
-        assertTrue(storage.equals(context.getService(storageRef)));
-    }
-    
-    @SuppressWarnings("rawtypes")
-    @Test
-    public void testConnectEnforcesPreCond() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        ServiceRegistration reg = context.registerService(DbService.class, dbService, null);
-        try {
-            dbService.connect();
-            fail("connect should check if db service is already registered");
-        } catch (IllegalStateException e) {
-            // pass
-            reg.unregister();
-        }
-        reg = context.registerService(Storage.class, storage, null);
-        try {
-            dbService.connect();
-            fail("connect should check if storage service is already registered");
-        } catch (IllegalStateException e) {
-            // pass
-            reg.unregister();
-        }
-    }
-    
-    @SuppressWarnings("rawtypes")
-    @Test
-    public void testDisConnectEnforcesPreCond() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        ServiceRegistration reg = context.registerService(DbService.class, dbService, null);
-        try {
-            // Storage == null
-            dbService.disconnect();
-            fail("disconnect should check if storage service is already registered");
-        } catch (IllegalStateException e) {
-            // pass
-            reg.unregister();
-        }
-        reg = context.registerService(Storage.class, storage, null);
-        try {
-            // DbService == null
-            dbService.disconnect();
-            fail("disconnect should check if db service is already registered");
-        } catch (IllegalStateException e) {
-            // pass
-            reg.unregister();
-        }
-    }
-
-    @Test
-    public void testDisconnect() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        assertNotNull(context.getServiceReference(DbService.class));
-        
-        dbService.disconnect();
-
-        assertTrue(connection.disconnectCalled);
-    }
-
-    @Test
-    public void testDisconnectUnregistersDbService() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        assertNotNull(context.getServiceReference(DbService.class));
-        
-        dbService.disconnect();
-
-        assertTrue(connection.disconnectCalled);
-        // disconnect unregisters DbService
-        assertNull(context.getServiceReference(DbService.class));
-    }
-    
-    @Test
-    public void testDisconnectUnregistersStorage() {
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        try {
-            dbService.connect();
-            // pass
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        assertNotNull(context.getServiceReference(Storage.class));
-        
-        dbService.disconnect();
-
-        assertTrue(connection.disconnectCalled);
-        
-        // disconnect unregisters Storage
-        assertNull(context.getServiceReference(Storage.class));
-    }
-    
-    @Test
-    public void canGetStorageUrl() {
-        String connectionURL = "http://test.example.com:8082";
-
-        DbService dbService = new DbServiceImpl(context, connectionURL, creds, sslConf);
-        assertEquals(connectionURL, dbService.getConnectionUrl());
-    }
-
-    @Test
-    public void canGetUsername() {
-        String connectionURL = "http://test.example.com:8082";
-
-        DbService dbService = new DbServiceImpl(context, connectionURL, creds, sslConf);
-        dbService.connect();
-
-        assertEquals(ImmediateConnection.USERNAME, dbService.getUserName());
-    }
-
-    @Test
-    public void testDisconnectUnsetsUsername() {
-        String connectionURL = "http://test.example.com:8082";
-
-        DbService dbService = new DbServiceImpl(context, connectionURL, creds, sslConf);
-        dbService.connect();
-
-        assertEquals(ImmediateConnection.USERNAME, dbService.getUserName());
-
-        dbService.disconnect();
-
-        assertEquals(Connection.UNSET_USERNAME, dbService.getUserName());
-    }
-    
-    @Test
-    public void testAddListener() {
-        ConnectionListener listener = mock(ConnectionListener.class);
-        Connection connection = mock(Connection.class);
-        when(storage.getConnection()).thenReturn(connection);
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        dbService.addConnectionListener(listener);
-        verify(connection).addListener(listener);
-    }
-    
-    @Test
-    public void testListenerGetsEvent() {
-        ConnectingConnectionListener listener = new ConnectingConnectionListener();
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-
-        ConnectingConnection connection = new ConnectingConnection();
-        when(storage.getConnection()).thenReturn(connection);
-        dbService.addConnectionListener(listener);
-        assertFalse(listener.eventReceived);
-        try {
-            dbService.connect();
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertTrue(connection.connectCalled);
-        assertTrue(listener.eventReceived);
-        listener.eventReceived = false;
-        dbService.removeConnectionListener(listener);
-        try {
-            dbService.disconnect();
-            dbService.connect();
-        } catch (ConnectionException e) {
-            fail();
-        }
-        assertFalse(listener.eventReceived);
-    }
-    
-    @Test
-    public void testRemoveListener() {
-        // Remove called regardless of listener actually being added
-        ConnectionListener listener = mock(ConnectionListener.class);
-        Connection connection = mock(Connection.class);
-        when(storage.getConnection()).thenReturn(connection);
-        DbService dbService = new DbServiceImpl(context, "http://ignored.example.com", creds, sslConf);
-        dbService.removeConnectionListener(listener);
-        verify(connection).removeListener(listener);
-    }
-    
-    static class DelayedConnection extends Connection {
-
-        boolean connectCalled = false;
-        boolean disconnectCalled = false;
-        private Thread thread;
-        boolean delayAwaited = false;
-        
-        @Override
-        public void connect() {
-            // delay connection and then fail
-            Runnable runnable = new Runnable() {
-                
-                @Override
-                public void run() {
-                    try {
-                        Thread.sleep(100);
-                        // This makes the connection fail (although delayed).
-                        delayAwaited = true;
-                        fireChanged(ConnectionStatus.FAILED_TO_CONNECT);
-                    } catch (InterruptedException e) {
-                        // ignore
-                    }
-                }
-            };
-            thread = new Thread(runnable);
-            thread.start();
-            connectCalled = true;
-        }
-
-        @Override
-        public void disconnect() {
-            Runnable runnable = new Runnable() {
-                
-                @Override
-                public void run() {
-                    try {
-                        Thread.sleep(100);
-                        delayAwaited = true;
-                        fireChanged(ConnectionStatus.DISCONNECTED);
-                    } catch (InterruptedException e) {
-                        // ignore
-                    }
-                }
-            };
-            thread = new Thread(runnable);
-            thread.start();
-            disconnectCalled = true;
-        }
-
-    }
-    
-    static class ImmediateConnection extends Connection {
-        
-        private static final String USERNAME = "username";
-
-        boolean connectCalled = false;
-        boolean disconnectCalled = false;
-
-        @Override
-        public void connect() {
-            connectCalled = true;
-            setUsername(USERNAME);
-            fireChanged(ConnectionStatus.CONNECTED);
-        }
-
-        @Override
-        public void disconnect() {
-            disconnectCalled = true;
-            fireChanged(ConnectionStatus.DISCONNECTED);
-        }
-
-    }
-    
-    static class ConnectingConnectionListener implements ConnectionListener {
-        
-        boolean eventReceived = false;
-
-        @Override
-        public void changed(ConnectionStatus newStatus) {
-            if (newStatus == ConnectionStatus.CONNECTING) {
-                eventReceived = true;
-            }
-        }
-        
-    }
-    
-    static class ConnectingConnection extends ImmediateConnection {
-        @Override
-        public void connect() {
-            fireChanged(ConnectionStatus.CONNECTING);
-            super.connect();
-        }
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/BasicDescriptorParserTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2043 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.any;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-import com.redhat.thermostat.storage.core.BackingStorage;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.CategoryAdapter;
-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.Remove;
-import com.redhat.thermostat.storage.core.Replace;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.model.AgentInformation;
-import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
-
-public class BasicDescriptorParserTest {
-
-    private BackingStorage storage;
-    private Query<AgentInformation> mockQuery;
-    private BasicDescriptorParser<AgentInformation> parser;
-    private Add<AgentInformation> mockAdd;
-    private Update<AgentInformation> mockUpdate;
-    private Replace<AgentInformation> mockReplace;
-    private Remove<AgentInformation> mockRemove;
-    
-    @SuppressWarnings("unchecked")
-    @Before
-    public void setup() {
-        storage = mock(BackingStorage.class);
-        mockQuery = mock(Query.class);
-        when(storage.createQuery(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockQuery);
-        // setup for ADD
-        mockAdd = mock(Add.class);
-        when(storage.createAdd(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockAdd);
-        // setup for UPDATE
-        mockUpdate = mock(Update.class);
-        when(storage.createUpdate(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockUpdate);
-        // setup for REMOVE
-        mockRemove = mock(Remove.class);
-        when(storage.createRemove(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockRemove);
-        // setup for REPLACE
-        mockReplace = mock(Replace.class);
-        when(storage.createReplace(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockReplace);
-    }
-    
-    @Test
-    public void verifyMatchingAggregateCountParamRegexp() {
-        Pattern p = Pattern.compile(BasicDescriptorParser.AGGREGATE_PARAM_REGEXP);
-        String empty = "";
-        Matcher matcher = p.matcher(empty);
-        assertTrue("Should match empty == no params", matcher.matches());
-        assertEquals(1, matcher.groupCount());
-        assertNull(matcher.group(1));
-        String parensWithName = "(foo)";
-        matcher = p.matcher(parensWithName);
-        assertTrue("Should match for a parameter name: " + parensWithName, matcher.matches());
-        assertEquals(1, matcher.groupCount());
-        assertEquals("foo", matcher.group(1));
-        String upLowUnderscore = "(Foo_Bar)";
-        matcher = p.matcher(upLowUnderscore);
-        assertTrue("Should match for a parameter name with upper/lowercase and underscore: "
-                   + upLowUnderscore, matcher.matches());
-        assertEquals(1, matcher.groupCount());
-        assertEquals("Foo_Bar", matcher.group(1));
-    }
-    
-    @Test
-    public void verifyRejectingAggregateCountParamRegexp() {
-        Pattern p = Pattern.compile(BasicDescriptorParser.AGGREGATE_PARAM_REGEXP);
-        String parensOnly = "()";
-        Matcher matcher = p.matcher(parensOnly);
-        assertFalse(parensOnly + " should not match", matcher.matches());
-        String spaceString = "( foo )";
-        matcher = p.matcher(spaceString);
-        assertFalse(spaceString + " should not match because it has spaces", matcher.matches());
-    }
-    
-    /*
-     * We allow QUERY-COUNT without any parameter for backwards compatibility
-     * Contrast this with QUERY-COUNT(foo). 
-     */
-    @Test
-    public void testParseAggregateCount() throws DescriptorParsingException {
-        String descFormat = "QUERY-COUNT %s WHERE 'a' = 'b'";
-        runAggregateCountTest(descFormat, AggregateFunction.COUNT);
-    }
-    
-    /*
-     * Query count with a specific optional key. Tests basic parsing.
-     */
-    @Test
-    public void testParseAggregateCountWithParam() throws DescriptorParsingException {
-        String descrString = "QUERY-COUNT(a) %s WHERE 'a' = 'b'";
-        runAggregateCountTest(descrString, AggregateFunction.COUNT);
-    }
-    
-    /*
-     * Distinct with a specific optional key. Tests basic parsing.
-     */
-    @Test
-    public void testParseAggregateDistinctWithParam() throws DescriptorParsingException {
-        String descrString = "QUERY-DISTINCT(a) %s WHERE 'a' = 'b'";
-        runAggregateCountTest(descrString, AggregateFunction.DISTINCT);
-    }
-    
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void testParseAggregateCountNoWhereClause() throws DescriptorParsingException {
-        AggregateQuery<AggregateCount> query = mock(AggregateQuery.class);
-        ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
-        when(storage.createAggregateQuery(eq(AggregateFunction.COUNT), captor.capture())).thenReturn(query);
-        // first adapt from the target category in order to be able to produce the
-        // right aggregate query with a different result type.
-        CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(AgentInfoDAO.CATEGORY);
-        Category<AggregateCount> aggregateCategory = adapter.getAdapted(AggregateCount.class);
-        String descrString = "QUERY-COUNT " + aggregateCategory.getName();
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(aggregateCategory, descrString);
-        BasicDescriptorParser<AggregateCount> parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AggregateCount> statement = (ParsedStatementImpl<AggregateCount>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertTrue(statement.getRawStatement() instanceof AggregateQuery);
-        Category<AggregateCount> capturedCategory = captor.getValue();
-        assertEquals(aggregateCategory, capturedCategory);
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNotNull(expn);
-        assertNull(expn.getWhereExpn());
-        assertNull(expn.getSortExpn());
-        assertNull(expn.getLimitExpn());
-    }
-    
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private void runAggregateCountTest(String descriptorFormat, AggregateFunction function) throws DescriptorParsingException {
-        AggregateQuery<AggregateCount> query = mock(AggregateQuery.class);
-        ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
-        when(storage.createAggregateQuery(eq(function), captor.capture())).thenReturn(query);
-        // first adapt from the target category in order to be able to produce the
-        // right aggregate query with a different result type.
-        CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(AgentInfoDAO.CATEGORY);
-        Category<AggregateCount> aggregateCategory = adapter.getAdapted(AggregateCount.class);
-        String descrString = String.format(descriptorFormat, aggregateCategory.getName());
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(aggregateCategory, descrString);
-        BasicDescriptorParser<AggregateCount> parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AggregateCount> statement = (ParsedStatementImpl<AggregateCount>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertTrue(statement.getRawStatement() instanceof AggregateQuery);
-        Category<AggregateCount> capturedCategory = captor.getValue();
-        assertEquals(aggregateCategory, capturedCategory);
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNotNull(expn);
-        WhereExpression where = expn.getWhereExpn();
-        assertNotNull(where);
-        assertNull(expn.getSortExpn());
-        assertNull(expn.getLimitExpn());
-    }
-    
-    @Test
-    public void testParseQueryCountWithAssertedParamValue() throws DescriptorParsingException {
-        String formatedDesc = "QUERY-COUNT(a) %s";
-        runParamAggregateAssertedValueTest(formatedDesc, AggregateFunction.COUNT);
-    }
-    
-    @Test
-    public void testParseQueryDistinctWithAssertedParamValue() throws DescriptorParsingException {
-        String formatedDesc = "QUERY-DISTINCT(a) %s";
-        runParamAggregateAssertedValueTest(formatedDesc, AggregateFunction.DISTINCT);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private void runParamAggregateAssertedValueTest(String aggregateDescFormat, AggregateFunction function) throws DescriptorParsingException {
-        AggregateQuery<AggregateCount> query = mock(AggregateQuery.class);
-        ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
-        when(storage.createAggregateQuery(eq(function), captor.capture())).thenReturn(query);
-        // first adapt from the target category in order to be able to produce the
-        // right aggregate query with a different result type.
-        CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(AgentInfoDAO.CATEGORY);
-        Category<AggregateCount> aggregateCategory = adapter.getAdapted(AggregateCount.class);
-        String descrString = String.format(aggregateDescFormat, aggregateCategory.getName());
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(aggregateCategory, descrString);
-        BasicDescriptorParser<AggregateCount> parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AggregateCount> statement = (ParsedStatementImpl<AggregateCount>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertTrue(statement.getRawStatement() instanceof AggregateQuery);
-        Key<?> aKey = new Key<>("a");
-        // Make sure the optional key is set
-        verify(query).setAggregateKey(eq(aKey));
-        Category<AggregateCount> capturedCategory = captor.getValue();
-        assertEquals(aggregateCategory, capturedCategory);
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNotNull(expn);
-        assertNull("No where expression expected", expn.getWhereExpn());
-        assertNull(expn.getSortExpn());
-        assertNull(expn.getLimitExpn());
-    }
-    
-    @Test
-    public void testParseQuerySimple() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName();
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression tree = statement.getSuffixExpression();
-        assertNull(tree.getLimitExpn());
-        assertNull(tree.getSortExpn());
-        assertNull(tree.getWhereExpn());
-    }
-    
-    @Test
-    public void testParseLongInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000000003L";
-        doTestType(descrString, 30000000003L, 0);
-    }
-    
-    @Test
-    public void testParseLongInWhere2() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000000003l";
-        doTestType(descrString, 30000000003L, 0);
-    }
-    
-    @Test
-    public void testParseLongInWhere3() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 3l";
-        doTestType(descrString, 3L, 0);
-    }
-    
-    @Test
-    public void testParseLongInWhere4() throws DescriptorParsingException {
-        long val = Long.MIN_VALUE;
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != " + val + "l";
-        doTestType(descrString, val, 0);
-    }
-    
-    @Test
-    public void testParseIntInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000";
-        doTestType(descrString, 30000, 0);
-    }
-    
-    @Test
-    public void testParseIntInWhere2() throws DescriptorParsingException {
-        int val = Integer.MAX_VALUE - 1;
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != " + val;
-        doTestType(descrString, val, 0);
-    }
-    
-    @Test
-    public void testParseIntInWhere3() throws DescriptorParsingException {
-        int val = Integer.MIN_VALUE;
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != " + val;
-        doTestType(descrString, val, 0);
-    }
-    
-    @Test
-    public void testParseBooleanInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != true";
-        doTestType(descrString, true, 0);
-    }
-    
-    @Test
-    public void testParseBooleanInWhere2() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != false";
-        doTestType(descrString, false, 0);
-    }
-    
-    @Test
-    public void testParseStringInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 'testing'";
-        doTestType(descrString, "testing", 0);
-    }
-    
-    @Test
-    public void testParseStringTypeFreeVarInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?s";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(String.class);
-        unfinished.setParameterIndex(0);
-        doTestType(descrString, unfinished, 1);
-    }
-    
-    @Test
-    public void testParseDoubleTypeFreeVarInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?d";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(double.class);
-        unfinished.setParameterIndex(0);
-        doTestType(descrString, unfinished, 1);
-    }
-    
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * String list free variable type in ADD.
-     */
-    @Test
-    public void testParseStringListTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support list types.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?s[";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(String[].class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * integer list free variable type in ADD.
-     */
-    @Test
-    public void testParseDoubleListTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support list types.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?d[";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(double[].class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-    
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * double list free variable type in ADD.
-     */
-    @Test
-    public void testParseIntListTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support list types.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?i[";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(int[].class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-    
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * boolean list free variable type in ADD.
-     */
-    @Test
-    public void testParseBooleanListTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support list types.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?b[";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(boolean[].class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-    
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * long list free variable type in ADD.
-     */
-    @Test
-    public void testParseLongListTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support list types.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?l[";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(long[].class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-    
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * long list free variable type in ADD.
-     */
-    @Test
-    public void testParsePojoTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support pojo type.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?p";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(Pojo.class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-    
-    /*
-     * SET clauses allow for setting list types. Test that it works for a
-     * Pojo list free variable type in ADD.
-     */
-    @Test
-    public void testParsePojoListTypeFreeVarInSetlist() throws DescriptorParsingException {
-        // use ADD since WHERE should not support list types.
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?p[";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(Pojo[].class);
-        unfinished.setParameterIndex(0);
-        doListTypeTest(descString, unfinished);
-    }
-
-    private void doListTypeTest(String descString, UnfinishedValueNode unfinished) {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertTrue(statement.getRawStatement() instanceof Add);
-        SuffixExpression suffix = statement.getSuffixExpression();
-        assertNotNull(suffix);
-        assertNull(suffix.getLimitExpn());
-        assertNull(suffix.getSortExpn());
-        assertNull(suffix.getWhereExpn());
-        SetList list = statement.getSetList();
-        assertNotNull(list);
-        List<SetListValue> mems = list.getValues();
-        assertEquals(1, mems.size());
-        SetListValue val = mems.get(0);
-        TerminalNode aKey = new TerminalNode(null);
-        aKey.setValue(new Key<>("a"));
-        assertEquals(aKey, val.getKey());
-        TerminalNode aVal = new TerminalNode(null);
-        aVal.setValue(unfinished);
-        assertEquals(aVal, val.getValue());
-    }
-    
-    @Test
-    public void testParseIntTypeFreeVarInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?i";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(int.class);
-        unfinished.setParameterIndex(0);
-        doTestType(descrString, unfinished, 1);
-    }
-    
-    @Test
-    public void testParseLongTypeFreeVarInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?l";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(long.class);
-        unfinished.setParameterIndex(0);
-        doTestType(descrString, unfinished, 1);
-    }
-    
-    @Test
-    public void testParseBooleanTypeFreeVarInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?b";
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setType(boolean.class);
-        unfinished.setParameterIndex(0);
-        doTestType(descrString, unfinished, 1);
-    }
-    
-    private void doTestType(String strDesc, Object bVal, int expNumFreeVars) throws DescriptorParsingException {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(expNumFreeVars, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression tree = statement.getSuffixExpression();
-        assertNull(tree.getLimitExpn());
-        assertNull(tree.getSortExpn());
-        assertNotNull(tree.getWhereExpn());
-        
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode notEquals = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(notEquals);
-        notEquals.setOperator(BinaryComparisonOperator.NOT_EQUAL_TO);
-        TerminalNode a = new TerminalNode(notEquals);
-        a.setValue(new Key<String>("a"));
-        TerminalNode b = new TerminalNode(notEquals);
-        b.setValue(bVal);
-        notEquals.setLeftChild(a);
-        notEquals.setRightChild(b);
-        
-        assertTrue(WhereExpressions.equals(expected, tree.getWhereExpn()));
-    }
-    
-    @Test
-    public void testParseNotEqualComparisonInWhere() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression tree = statement.getSuffixExpression();
-        assertNull(tree.getLimitExpn());
-        assertNull(tree.getSortExpn());
-        assertNotNull(tree.getWhereExpn());
-        
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode notEquals = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(notEquals);
-        notEquals.setOperator(BinaryComparisonOperator.NOT_EQUAL_TO);
-        TerminalNode a = new TerminalNode(notEquals);
-        a.setValue(new Key<String>("a"));
-        TerminalNode b = new TerminalNode(notEquals);
-        b.setValue("b");
-        notEquals.setLeftChild(a);
-        notEquals.setRightChild(b);
-        
-        assertTrue(WhereExpressions.equals(expected, tree.getWhereExpn()));
-    }
-    
-    @Test
-    public void testParseQuerySimpleWithLimit() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?i";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(1, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNotNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNull(expn.getWhereExpn());
-        LimitExpression limitExp = expn.getLimitExpn();
-        assertTrue(limitExp.getValue() instanceof UnfinishedLimitValue);
-        UnfinishedLimitValue value = (UnfinishedLimitValue)limitExp.getValue();
-        assertEquals(0, value.getParameterIndex());
-    }
-    
-    @Test
-    public void testParseSortMultiple() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT 'a' ASC , 'b' DSC , 'c' ASC";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        SortExpression sortExpn = suffixExpn.getSortExpn();
-        assertNotNull(sortExpn);
-        assertNull(suffixExpn.getLimitExpn());
-        assertNull(suffixExpn.getWhereExpn());
-        List<SortMember> list = sortExpn.getMembers();
-        assertNotNull(list);
-        assertEquals(3, list.size());
-        assertEquals(SortDirection.ASCENDING, list.get(0).getDirection());
-        assertEquals(SortDirection.DESCENDING, list.get(1).getDirection());
-        assertEquals(SortDirection.ASCENDING, list.get(2).getDirection());
-        assertEquals("a", list.get(0).getSortKey());
-        assertEquals("b", list.get(1).getSortKey());
-        assertEquals("c", list.get(2).getSortKey());
-    }
-    
-    @Test
-    public void testParseQueryWithMultipleConcunctions() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' AND 'c' = 'd' AND 'e' < ?i";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(1, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNotNull(expn.getWhereExpn());
-        WhereExpression where = expn.getWhereExpn();
-        // build the expected expression tree
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode and1 = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(and1);
-        BinaryExpressionNode and2 = new BinaryExpressionNode(and1);
-        and1.setLeftChild(and2);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode equality1 = new BinaryExpressionNode(and2);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        and2.setLeftChild(equality1);
-        equality1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality1);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality1.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality1);
-        b.setValue("b");
-        equality1.setRightChild(b);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(and2);
-        and2.setRightChild(equality2);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(and1);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        and1.setRightChild(lessThan);
-        TerminalNode e = new TerminalNode(lessThan);
-        Key<Integer> eKey = new Key<>("e");
-        e.setValue(eKey);
-        lessThan.setLeftChild(e);
-        UnfinishedValueNode f = new UnfinishedValueNode();
-        f.setParameterIndex(0);
-        f.setType(int.class);
-        f.setLHS(false);
-        TerminalNode fReal = new TerminalNode(lessThan);
-        fReal.setValue(f);
-        lessThan.setRightChild(fReal);
-        
-        assertTrue( WhereExpressions.equals(expected, where));
-    }
-    
-    @Test
-    public void testParseQueryWithMultipleConcunctions2() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' AND 'c' = 'd' AND 'e' < 'f' AND 'g' >= 'h'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNotNull(expn.getWhereExpn());
-        WhereExpression where = expn.getWhereExpn();
-        // build the expected expression tree
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode and1 = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(and1);
-        BinaryExpressionNode and2 = new BinaryExpressionNode(and1);
-        and1.setLeftChild(and2);
-        BinaryExpressionNode and3 = new BinaryExpressionNode(and2);
-        and3.setOperator(BinaryLogicalOperator.AND);
-        and2.setLeftChild(and3);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode equality1 = new BinaryExpressionNode(and3);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        and3.setLeftChild(equality1);
-        equality1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality1);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality1.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality1);
-        b.setValue("b");
-        equality1.setRightChild(b);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(and3);
-        and3.setRightChild(equality2);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(and2);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        and2.setRightChild(lessThan);
-        TerminalNode e = new TerminalNode(lessThan);
-        Key<String> eKey = new Key<>("e");
-        e.setValue(eKey);
-        lessThan.setLeftChild(e);
-        TerminalNode f = new TerminalNode(lessThan);
-        f.setValue("f");
-        lessThan.setRightChild(f);
-        BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(and1);
-        greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-        TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key<String> gKey = new Key<>("g");
-        g.setValue(gKey);
-        greaterOrEqual.setLeftChild(g);
-        TerminalNode h = new TerminalNode(greaterOrEqual);
-        h.setValue("h");
-        greaterOrEqual.setRightChild(h);
-        and1.setRightChild(greaterOrEqual);
-        
-        assertTrue( WhereExpressions.equals(expected, where));
-    }
-    
-    @Test
-    public void testParseQueryWithMultipleDisjunctions() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' OR 'c' = 'd' OR 'e' < ?i";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(1, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNotNull(expn.getWhereExpn());
-        
-        WhereExpression where = expn.getWhereExpn();
-        // build the expected expression tree
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode or1 = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(or1);
-        BinaryExpressionNode or2 = new BinaryExpressionNode(or1);
-        or1.setLeftChild(or2);
-        or1.setOperator(BinaryLogicalOperator.OR);
-        BinaryExpressionNode equality1 = new BinaryExpressionNode(or2);
-        or2.setOperator(BinaryLogicalOperator.OR);
-        or2.setLeftChild(equality1);
-        equality1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality1);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality1.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality1);
-        b.setValue("b");
-        equality1.setRightChild(b);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(or2);
-        or2.setRightChild(equality2);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(or1);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        or1.setRightChild(lessThan);
-        TerminalNode e = new TerminalNode(lessThan);
-        Key<Integer> eKey = new Key<>("e");
-        e.setValue(eKey);
-        lessThan.setLeftChild(e);
-        UnfinishedValueNode f = new UnfinishedValueNode();
-        f.setParameterIndex(0);
-        f.setType(int.class);
-        f.setLHS(false);
-        TerminalNode fReal = new TerminalNode(lessThan);
-        fReal.setValue(f);
-        lessThan.setRightChild(fReal);
-        
-        assertTrue( WhereExpressions.equals(expected, where));
-    }
-    
-    @Test
-    public void testParseQueryWithMultipleDisjunctions2() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' OR 'c' = 'd' OR 'e' < 'f' OR 'g' >= 'h'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNotNull(expn.getWhereExpn());
-        
-        WhereExpression where = expn.getWhereExpn();
-        // build the expected expression tree
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode or1 = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(or1);
-        BinaryExpressionNode or2 = new BinaryExpressionNode(or1);
-        or1.setLeftChild(or2);
-        BinaryExpressionNode or3 = new BinaryExpressionNode(or2);
-        or3.setOperator(BinaryLogicalOperator.OR);
-        or2.setLeftChild(or3);
-        or1.setOperator(BinaryLogicalOperator.OR);
-        BinaryExpressionNode equality1 = new BinaryExpressionNode(or3);
-        or2.setOperator(BinaryLogicalOperator.OR);
-        or3.setLeftChild(equality1);
-        equality1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality1);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality1.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality1);
-        b.setValue("b");
-        equality1.setRightChild(b);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(or3);
-        or3.setRightChild(equality2);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(or2);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        or2.setRightChild(lessThan);
-        TerminalNode e = new TerminalNode(lessThan);
-        Key<String> eKey = new Key<>("e");
-        e.setValue(eKey);
-        lessThan.setLeftChild(e);
-        TerminalNode f = new TerminalNode(lessThan);
-        f.setValue("f");
-        lessThan.setRightChild(f);
-        BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(or1);
-        greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-        TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key<String> gKey = new Key<>("g");
-        g.setValue(gKey);
-        greaterOrEqual.setLeftChild(g);
-        TerminalNode h = new TerminalNode(greaterOrEqual);
-        h.setValue("h");
-        greaterOrEqual.setRightChild(h);
-        or1.setRightChild(greaterOrEqual);
-        
-        assertTrue( WhereExpressions.equals(expected, where));
-    }
-    
-    @Test
-    public void testParseQueryWithMultipleConDisjunctions() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' OR 'c' = 'd' OR 'e' < 'f' OR 'g' >= 'h' AND 'x' = 'y' AND 'u' = 'w' AND 's' = 't'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>) parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNotNull(expn.getWhereExpn());
-        
-        WhereExpression where = expn.getWhereExpn();
-        // build the expected expression tree
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode and3 = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(and3);
-        and3.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode and2 = new BinaryExpressionNode(and3);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode and1 = new BinaryExpressionNode(and2);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode equality3 = new BinaryExpressionNode(and1);
-        equality3.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode x = new TerminalNode(equality3);
-        x.setValue(new Key<>("x"));
-        TerminalNode y = new TerminalNode(equality3);
-        y.setValue("y");
-        equality3.setLeftChild(x);
-        equality3.setRightChild(y);
-        and1.setRightChild(equality3);
-        and3.setLeftChild(and2);
-        and2.setLeftChild(and1);
-        BinaryExpressionNode equality4 = new BinaryExpressionNode(and2);
-        equality4.setOperator(BinaryComparisonOperator.EQUALS);
-        and2.setRightChild(equality4);
-        TerminalNode u = new TerminalNode(equality4);
-        u.setValue(new Key<>("u"));
-        equality4.setLeftChild(u);
-        TerminalNode w = new TerminalNode(equality4);
-        w.setValue("w");
-        equality4.setRightChild(w);
-        BinaryExpressionNode equality5 = new BinaryExpressionNode(and3);
-        equality5.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode s = new TerminalNode(equality5);
-        s.setValue(new Key<>("s"));
-        TerminalNode t = new TerminalNode(equality5);
-        t.setValue("t");
-        equality5.setLeftChild(s);
-        equality5.setRightChild(t);
-        and3.setRightChild(equality5);
-        BinaryExpressionNode or3 = new BinaryExpressionNode(and1);
-        BinaryExpressionNode or2 = new BinaryExpressionNode(or3);
-        BinaryExpressionNode or1 = new BinaryExpressionNode(or2);
-        or3.setOperator(BinaryLogicalOperator.OR);
-        or2.setOperator(BinaryLogicalOperator.OR);
-        or1.setOperator(BinaryLogicalOperator.OR);
-        or3.setLeftChild(or2);
-        or2.setLeftChild(or1);
-        BinaryExpressionNode equality1 = new BinaryExpressionNode(or1);
-        or1.setLeftChild(equality1);
-        equality1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality1);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality1.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality1);
-        b.setValue("b");
-        equality1.setRightChild(b);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(or1);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        or1.setRightChild(equality2);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(or2);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        or2.setRightChild(lessThan);
-        or2.setLeftChild(or1);
-        TerminalNode e = new TerminalNode(lessThan);
-        Key<String> eKey = new Key<>("e");
-        e.setValue(eKey);
-        lessThan.setLeftChild(e);
-        TerminalNode f = new TerminalNode(lessThan);
-        f.setValue("f");
-        lessThan.setRightChild(f);
-        BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(or3);
-        greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-        TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key<String> gKey = new Key<>("g");
-        g.setValue(gKey);
-        greaterOrEqual.setLeftChild(g);
-        TerminalNode h = new TerminalNode(greaterOrEqual);
-        h.setValue("h");
-        greaterOrEqual.setRightChild(h);
-        or3.setRightChild(greaterOrEqual);
-        or3.setLeftChild(or2);
-        and1.setLeftChild(or3);
-        
-        assertTrue(WhereExpressions.equals(expected, where));
-    }
-    
-    @Test
-    public void testParseQueryWithMultipleConDisjunctionsNegations() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' OR NOT 'c' = 'd' OR 'e' < 'f' OR 'g' >= 'h' AND NOT 'x' = 'y' AND 'u' = 'w' AND 's' = 't'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>) parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression expn = statement.getSuffixExpression();
-        assertNull(expn.getLimitExpn());
-        assertNull(expn.getSortExpn());
-        assertNotNull(expn.getWhereExpn());
-        
-        WhereExpression where = expn.getWhereExpn();
-        // build the expected expression tree
-        WhereExpression expected = new WhereExpression();
-        BinaryExpressionNode and3 = new BinaryExpressionNode(expected.getRoot());
-        expected.getRoot().setValue(and3);
-        and3.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode and2 = new BinaryExpressionNode(and3);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode and1 = new BinaryExpressionNode(and2);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        NotBooleanExpressionNode not2 = new NotBooleanExpressionNode(and1);
-        BinaryExpressionNode equality3 = new BinaryExpressionNode(not2);
-        not2.setValue(equality3);
-        equality3.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode x = new TerminalNode(equality3);
-        x.setValue(new Key<String>("x"));
-        TerminalNode y = new TerminalNode(equality3);
-        y.setValue("y");
-        equality3.setLeftChild(x);
-        equality3.setRightChild(y);
-        and1.setRightChild(not2);
-        and3.setLeftChild(and2);
-        and2.setLeftChild(and1);
-        BinaryExpressionNode equality4 = new BinaryExpressionNode(and2);
-        equality4.setOperator(BinaryComparisonOperator.EQUALS);
-        and2.setRightChild(equality4);
-        TerminalNode u = new TerminalNode(equality4);
-        u.setValue(new Key<String>("u"));
-        equality4.setLeftChild(u);
-        TerminalNode w = new TerminalNode(equality4);
-        w.setValue("w");
-        equality4.setRightChild(w);
-        BinaryExpressionNode equality5 = new BinaryExpressionNode(and3);
-        equality5.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode s = new TerminalNode(equality5);
-        s.setValue(new Key<String>("s"));
-        TerminalNode t = new TerminalNode(equality5);
-        t.setValue("t");
-        equality5.setLeftChild(s);
-        equality5.setRightChild(t);
-        and3.setRightChild(equality5);
-        BinaryExpressionNode or3 = new BinaryExpressionNode(and1);
-        BinaryExpressionNode or2 = new BinaryExpressionNode(or3);
-        BinaryExpressionNode or1 = new BinaryExpressionNode(or2);
-        or3.setOperator(BinaryLogicalOperator.OR);
-        or2.setOperator(BinaryLogicalOperator.OR);
-        or1.setOperator(BinaryLogicalOperator.OR);
-        or3.setLeftChild(or2);
-        or2.setLeftChild(or1);
-        BinaryExpressionNode equality1 = new BinaryExpressionNode(or1);
-        or1.setLeftChild(equality1);
-        equality1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality1);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality1.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality1);
-        b.setValue("b");
-        equality1.setRightChild(b);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(or1);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        NotBooleanExpressionNode not1 = new NotBooleanExpressionNode(or1);
-        not1.setValue(equality2);
-        or1.setRightChild(not1);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(or2);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        or2.setRightChild(lessThan);
-        or2.setLeftChild(or1);
-        TerminalNode e = new TerminalNode(lessThan);
-        Key<String> eKey = new Key<>("e");
-        e.setValue(eKey);
-        lessThan.setLeftChild(e);
-        TerminalNode f = new TerminalNode(lessThan);
-        f.setValue("f");
-        lessThan.setRightChild(f);
-        BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(or3);
-        greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-        TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key<String> gKey = new Key<>("g");
-        g.setValue(gKey);
-        greaterOrEqual.setLeftChild(g);
-        TerminalNode h = new TerminalNode(greaterOrEqual);
-        h.setValue("h");
-        greaterOrEqual.setRightChild(h);
-        or3.setRightChild(greaterOrEqual);
-        or3.setLeftChild(or2);
-        and1.setLeftChild(or3);
-        
-        assertTrue(WhereExpressions.equals(expected, where));
-    }
-    
-    @Test
-    public void testParseQueryWhereAndSortMultiple() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' < 'b' AND 'c' = ?s OR NOT 'x' >= ?i SORT 'a' ASC , 'b' DSC , 'c' ASC";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>) parser.parse();
-        assertEquals(2, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNotNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        List<SortMember> list = suffixExpn.getSortExpn().getMembers();
-        assertNotNull(list);
-        assertEquals(3, list.size());
-        assertEquals(SortDirection.ASCENDING, list.get(0).getDirection());
-        assertEquals(SortDirection.DESCENDING, list.get(1).getDirection());
-        assertEquals(SortDirection.ASCENDING, list.get(2).getDirection());
-        assertEquals("a", list.get(0).getSortKey());
-        assertEquals("b", list.get(1).getSortKey());
-        assertEquals("c", list.get(2).getSortKey());
-        // build the expected expression tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode or = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(or);
-        or.setOperator(BinaryLogicalOperator.OR);
-        BinaryExpressionNode and = new BinaryExpressionNode(or);
-        and.setOperator(BinaryLogicalOperator.AND);
-        or.setLeftChild(and);
-        NotBooleanExpressionNode not = new NotBooleanExpressionNode(or);
-        or.setRightChild(not);
-        BinaryExpressionNode unequality = new BinaryExpressionNode(and);
-        unequality.setOperator(BinaryComparisonOperator.LESS_THAN);
-        TerminalNode a = new TerminalNode(unequality);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        unequality.setLeftChild(a);
-        TerminalNode b = new TerminalNode(unequality);
-        b.setValue("b");
-        unequality.setRightChild(b);
-        and.setLeftChild(unequality);
-        BinaryExpressionNode equality = new BinaryExpressionNode(and);
-        equality.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality.setLeftChild(c);
-        UnfinishedValueNode patch1 = new UnfinishedValueNode();
-        patch1.setParameterIndex(0);
-        patch1.setLHS(false);
-        patch1.setType(String.class);
-        TerminalNode d = new TerminalNode(equality);
-        d.setValue(patch1);
-        equality.setRightChild(d);
-        and.setRightChild(equality);
-        BinaryExpressionNode greaterEqual = new BinaryExpressionNode(not);
-        not.setValue(greaterEqual);
-        greaterEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
-        TerminalNode x = new TerminalNode(greaterEqual);
-        Key<Integer> xKey = new Key<>("x");
-        x.setValue(xKey);
-        greaterEqual.setLeftChild(x);
-        UnfinishedValueNode patch2 = new UnfinishedValueNode();
-        patch2.setParameterIndex(1);
-        patch2.setLHS(false);
-        patch2.setType(int.class);
-        TerminalNode y = new TerminalNode(greaterEqual);
-        y.setValue(patch2);
-        greaterEqual.setRightChild(y);
-        // finally assert equality
-        assertTrue( WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-    
-    @Test
-    public void testParseQueryWhereOrSortMultiple() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' < 'b' OR 'c' = ?s SORT 'a' ASC , ?s DSC , 'c' ASC";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>) parser.parse();
-        assertEquals(2, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNotNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        SortExpression sortExp = suffixExpn.getSortExpn();
-        List<SortMember> list = sortExp.getMembers();
-        assertNotNull(list);
-        assertEquals(3, list.size());
-        assertEquals(SortDirection.ASCENDING, list.get(0).getDirection());
-        assertEquals(SortDirection.DESCENDING, list.get(1).getDirection());
-        assertEquals(SortDirection.ASCENDING, list.get(2).getDirection());
-        assertEquals("a", list.get(0).getSortKey());
-        UnfinishedSortKey unfinished = new UnfinishedSortKey();
-        unfinished.setParameterIndex(1);
-        assertEquals(unfinished, list.get(1).getSortKey());
-        assertEquals("c", list.get(2).getSortKey());
-        // build the expected expression tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode or = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(or);
-        or.setOperator(BinaryLogicalOperator.OR);
-        BinaryExpressionNode unequality = new BinaryExpressionNode(or);
-        unequality.setOperator(BinaryComparisonOperator.LESS_THAN);
-        TerminalNode a = new TerminalNode(unequality);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        unequality.setLeftChild(a);
-        TerminalNode b = new TerminalNode(unequality);
-        b.setValue("b");
-        unequality.setRightChild(b);
-        or.setLeftChild(unequality);
-        BinaryExpressionNode equality = new BinaryExpressionNode(or);
-        equality.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality);
-        Key<String> cKey = new Key<>("c");
-        c.setValue(cKey);
-        equality.setLeftChild(c);
-        UnfinishedValueNode patch1 = new UnfinishedValueNode();
-        patch1.setParameterIndex(0);
-        patch1.setLHS(false);
-        patch1.setType(String.class);
-        TerminalNode d = new TerminalNode(equality);
-        d.setValue(patch1);
-        equality.setRightChild(d);
-        or.setRightChild(equality);
-        assertTrue(WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-    
-    @Test
-    public void testParseQuerySimpleWhereAndSimpleSort() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' < 'b' SORT 'a' DSC";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNotNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        SortExpression sortExp = suffixExpn.getSortExpn();
-        List<SortMember> list = sortExp.getMembers();
-        assertNotNull(list);
-        assertEquals(1, list.size());
-        assertEquals(SortDirection.DESCENDING, list.get(0).getDirection());
-        assertEquals("a", list.get(0).getSortKey());
-        // build the expected expression tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode unequality = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(unequality);
-        unequality.setOperator(BinaryComparisonOperator.LESS_THAN);
-        TerminalNode a = new TerminalNode(unequality);
-        @SuppressWarnings("rawtypes")
-        Key aKey = new Key("a");
-        a.setValue(aKey);
-        unequality.setLeftChild(a);
-        TerminalNode b = new TerminalNode(unequality);
-        b.setValue("b");
-        unequality.setRightChild(b);
-        assertTrue(WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-    
-    @Test
-    public void testParseQuerySimpleWithOneWhere() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE '" + Key.AGENT_ID.getName() + "' = ?s";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            fail(e.getMessage());
-        }
-        assertEquals(1, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        // build the expected expression tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode equality = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(equality);
-        equality.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality);
-        @SuppressWarnings("rawtypes")
-        Key aKey = new Key(Key.AGENT_ID.getName());
-        a.setValue(aKey);
-        equality.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality);
-        UnfinishedValueNode node = new UnfinishedValueNode();
-        node.setParameterIndex(0);
-        node.setLHS(false);
-        node.setType(String.class);
-        b.setValue(node);
-        equality.setRightChild(b);
-        assertTrue(WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-
-    @Test
-    public void testParseSimpleWithAndOr() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE '" + Key.AGENT_ID.getName() + "' = ?s" +
-                            " AND ?s < ?b OR 'a' = 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertEquals(3, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        // build the expected expression tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode or = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(or);
-        or.setOperator(BinaryLogicalOperator.OR);
-        BinaryExpressionNode and = new BinaryExpressionNode(or);
-        and.setOperator(BinaryLogicalOperator.AND);
-        or.setLeftChild(and);
-        BinaryExpressionNode equality = new BinaryExpressionNode(and);
-        equality.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        equality.setLeftChild(a);
-        TerminalNode b = new TerminalNode(equality);
-        b.setValue("b");
-        equality.setRightChild(b);
-        or.setRightChild(equality);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(and);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        Key<String> cKey = new Key<>(Key.AGENT_ID.getName());
-        c.setValue(cKey);
-        equality2.setLeftChild(c);
-        UnfinishedValueNode patch1 = new UnfinishedValueNode();
-        patch1.setParameterIndex(0);
-        patch1.setLHS(false);
-        patch1.setType(String.class);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue(patch1);
-        equality2.setRightChild(d);
-        and.setLeftChild(equality2);
-        BinaryExpressionNode lessThan = new BinaryExpressionNode(and);
-        lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
-        UnfinishedValueNode patch = new UnfinishedValueNode();
-        patch.setParameterIndex(1);
-        patch.setType(String.class);
-        patch.setLHS(true);
-        TerminalNode x = new TerminalNode(lessThan);
-        x.setValue(patch);
-        lessThan.setLeftChild(x);
-        UnfinishedValueNode patch2 = new UnfinishedValueNode();
-        patch2.setLHS(false);
-        patch2.setParameterIndex(2);
-        patch2.setType(boolean.class);
-        TerminalNode y = new TerminalNode(lessThan);
-        y.setValue(patch2);
-        lessThan.setRightChild(y);
-        and.setRightChild(lessThan);
-        assertTrue(WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-
-    @Test
-    public void testParseSimpleWithAnd() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?s AND ?s = 'd'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertEquals(2, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        // build the expected expression tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(and);
-        and.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode equality = new BinaryExpressionNode(and);
-        equality.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality);
-        @SuppressWarnings("rawtypes")
-        Key aKey = new Key("a");
-        a.setValue(aKey);
-        equality.setLeftChild(a);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setParameterIndex(0);
-        unfinished.setLHS(false);
-        unfinished.setType(String.class);
-        TerminalNode b = new TerminalNode(equality);
-        b.setValue(unfinished);
-        equality.setRightChild(b);
-        and.setLeftChild(equality);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(and);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        UnfinishedValueNode patch1 = new UnfinishedValueNode();
-        patch1.setParameterIndex(1);
-        patch1.setType(String.class);
-        patch1.setLHS(true);
-        c.setValue(patch1);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        and.setRightChild(equality2);
-        assertTrue(WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-
-    @Test
-    public void testParseSimpleWithNotOR() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE NOT 'a' = ?s OR ?s = 'd'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertEquals(2, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        // build the expected parse tree
-        WhereExpression expn = new WhereExpression();
-        BinaryExpressionNode or = new BinaryExpressionNode(expn.getRoot());
-        expn.getRoot().setValue(or);
-        or.setOperator(BinaryLogicalOperator.OR);
-        NotBooleanExpressionNode notNode = new NotBooleanExpressionNode(or);
-        BinaryExpressionNode comparison = new BinaryExpressionNode(notNode);
-        notNode.setValue(comparison);
-        or.setLeftChild(notNode);
-        comparison.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode rightCompTerm = new TerminalNode(comparison);
-        TerminalNode leftCompTerm = new TerminalNode(comparison);
-        @SuppressWarnings("rawtypes")
-        Key aKey = new Key("a");
-        leftCompTerm.setValue(aKey);
-        UnfinishedValueNode patch1 = new UnfinishedValueNode();
-        patch1.setParameterIndex(0);
-        patch1.setType(String.class);
-        patch1.setLHS(false);
-        rightCompTerm.setValue(patch1);
-        comparison.setLeftChild(leftCompTerm);
-        comparison.setRightChild(rightCompTerm);
-        BinaryExpressionNode otherComparison = new BinaryExpressionNode(or);
-        otherComparison.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode leftUnfinished = new TerminalNode(otherComparison);
-        UnfinishedValueNode patch2 = new UnfinishedValueNode();
-        patch2.setParameterIndex(1);
-        patch2.setLHS(true);
-        patch2.setType(String.class);
-        leftUnfinished.setValue(patch2);
-        TerminalNode other = new TerminalNode(otherComparison);
-        other.setValue("d");
-        otherComparison.setLeftChild(leftUnfinished);
-        otherComparison.setRightChild(other);
-        or.setRightChild(otherComparison);
-        assertTrue(WhereExpressions.equals(expn, suffixExpn.getWhereExpn()));
-    }
-
-    @Test
-    public void testParseSimpleWithOr() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?s OR ?s = 'd'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertEquals(2, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getLimitExpn());
-        assertNotNull(suffixExpn.getWhereExpn());
-        // build the expected parse tree
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(and);
-        and.setOperator(BinaryLogicalOperator.OR);
-        BinaryExpressionNode equality = new BinaryExpressionNode(and);
-        equality.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(equality);
-        @SuppressWarnings("rawtypes")
-        Key aKey = new Key("a");
-        a.setValue(aKey);
-        equality.setLeftChild(a);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setParameterIndex(0);
-        unfinished.setType(String.class);
-        unfinished.setLHS(false);
-        TerminalNode b = new TerminalNode(equality);
-        b.setValue(unfinished);
-        equality.setRightChild(b);
-        and.setLeftChild(equality);
-        BinaryExpressionNode equality2 = new BinaryExpressionNode(and);
-        equality2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode c = new TerminalNode(equality2);
-        UnfinishedValueNode patch1 = new UnfinishedValueNode();
-        patch1.setParameterIndex(1);
-        patch1.setType(String.class);
-        patch1.setLHS(true);
-        c.setValue(patch1);
-        equality2.setLeftChild(c);
-        TerminalNode d = new TerminalNode(equality2);
-        d.setValue("d");
-        equality2.setRightChild(d);
-        and.setRightChild(equality2);
-        assertTrue(WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
-    }
-    
-    @Test
-    public void testParseSimpleWithLimit() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT 1";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertEquals(0, statement.getNumParams());
-        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
-        SuffixExpression suffixExpn = statement.getSuffixExpression();
-        assertNull(suffixExpn.getSortExpn());
-        assertNull(suffixExpn.getWhereExpn());
-        assertNotNull(suffixExpn.getLimitExpn());
-        assertEquals(1, suffixExpn.getLimitExpn().getValue());
-    }
-    
-    @Test
-    public void testParseAddBasic() throws DescriptorParsingException {
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = 'b' , 'c' = ?s";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertTrue(statement.getRawStatement() instanceof Add);
-        SuffixExpression suffix = statement.getSuffixExpression();
-        assertNotNull(suffix);
-        WhereExpression where = suffix.getWhereExpn();
-        LimitExpression limit = suffix.getLimitExpn();
-        SortExpression sort = suffix.getSortExpn();
-        assertNull(where);
-        assertNull(limit);
-        assertNull(sort);
-        SetList setList = statement.getSetList();
-        assertNotNull(setList);
-        List<SetListValue> valuesList = setList.getValues();
-        assertEquals(2, valuesList.size());
-        SetListValue first = valuesList.get(0);
-        SetListValue second = valuesList.get(1);
-        TerminalNode a = new TerminalNode(null);
-        a.setValue(new Key<>("a"));
-        TerminalNode b = new TerminalNode(null);
-        b.setValue("b");
-        SetListValue firstExpected = new SetListValue();
-        firstExpected.setKey(a);
-        firstExpected.setValue(b);
-        assertEquals(firstExpected, first);
-        TerminalNode c = new TerminalNode(null);
-        c.setValue(new Key<>("c"));
-        UnfinishedValueNode dVal = new UnfinishedValueNode();
-        dVal.setType(String.class);
-        dVal.setLHS(false);
-        dVal.setParameterIndex(0);
-        TerminalNode d = new TerminalNode(null);
-        d.setValue(dVal);
-        SetListValue secondExpected = new SetListValue();
-        secondExpected.setKey(c);
-        secondExpected.setValue(d);
-        assertEquals(secondExpected, second);
-    }
-    
-    @Test
-    public void testParseUpdateBasic() throws DescriptorParsingException {
-        String descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = 'b' , 'c' = ?s WHERE 'foo' != ?i";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        ParsedStatementImpl<AgentInformation> statement = null; 
-        try {
-            statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
-        } catch (DescriptorParsingException e) {
-            e.printStackTrace();
-            fail(e.getMessage());
-        }
-        assertTrue(statement.getRawStatement() instanceof Update);
-        SuffixExpression suffix = statement.getSuffixExpression();
-        assertNotNull(suffix);
-        WhereExpression where = suffix.getWhereExpn();
-        LimitExpression limit = suffix.getLimitExpn();
-        SortExpression sort = suffix.getSortExpn();
-        assertNotNull(where);
-        assertNull(limit);
-        assertNull(sort);
-        SetList setList = statement.getSetList();
-        assertNotNull(setList);
-        List<SetListValue> valuesList = setList.getValues();
-        assertEquals(2, valuesList.size());
-        SetListValue first = valuesList.get(0);
-        SetListValue second = valuesList.get(1);
-        TerminalNode a = new TerminalNode(null);
-        a.setValue(new Key<>("a"));
-        TerminalNode b = new TerminalNode(null);
-        b.setValue("b");
-        SetListValue firstExpected = new SetListValue();
-        firstExpected.setKey(a);
-        firstExpected.setValue(b);
-        assertEquals(firstExpected, first);
-        TerminalNode c = new TerminalNode(null);
-        c.setValue(new Key<>("c"));
-        UnfinishedValueNode dVal = new UnfinishedValueNode();
-        dVal.setType(String.class);
-        dVal.setLHS(false);
-        dVal.setParameterIndex(0);
-        TerminalNode d = new TerminalNode(null);
-        d.setValue(dVal);
-        SetListValue secondExpected = new SetListValue();
-        secondExpected.setKey(c);
-        secondExpected.setValue(d);
-        assertEquals(secondExpected, second);
-        // Build expected where expn
-        WhereExpression expectedWhere = new WhereExpression();
-        BinaryExpressionNode equality = new BinaryExpressionNode(expectedWhere.getRoot());
-        expectedWhere.getRoot().setValue(equality);
-        equality.setOperator(BinaryComparisonOperator.NOT_EQUAL_TO);
-        TerminalNode foo = new TerminalNode(equality);
-        @SuppressWarnings("rawtypes")
-        Key fooKey = new Key("foo");
-        foo.setValue(fooKey);
-        equality.setLeftChild(foo);
-        TerminalNode fooVal = new TerminalNode(equality);
-        UnfinishedValueNode node = new UnfinishedValueNode();
-        node.setParameterIndex(1);
-        node.setLHS(false);
-        node.setType(int.class);
-        fooVal.setValue(node);
-        equality.setRightChild(fooVal);
-        assertTrue(WhereExpressions.equals(expectedWhere, where));
-    }
-    
-    // TODO: Add basic parse tests for REMOVE/REPLACE
-    
-    @Test
-    public void rejectLongValAsIntType() throws DescriptorParsingException {
-        // 30000000003 > Integer.MAX_VALUE; needs to be preceded by 'l/L'
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000000003";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Illegal terminal type."));
-        }
-    }
-
-    @Test
-    public void rejectLimitWhichIsNotInt() {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT illegal";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            assertEquals("Invalid limit expression. 'illegal' not an integer", e.getMessage());
-        }
-    }
-
-    @Test
-    public void rejectLHSnotString() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE a < 1";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Expected string value. Got term ->a<-"));
-        }
-    }
-    
-    @Test
-    public void rejectSpaceInQueryCountParam() {
-        String descFormat = "QUERY-COUNT(' a) %s";
-        String expnMsg = "Unknown statement type: 'QUERY-COUNT(''";
-        runRejectQueryCountTest(descFormat, expnMsg);
-    }
-    
-    @Test
-    public void rejectSpaceInQueryCountParam2() {
-        String descFormat = "QUERY-COUNT(Abc ) %s";
-        String expnMsg = "Unknown statement type: 'QUERY-COUNT(Abc'";
-        runRejectQueryCountTest(descFormat, expnMsg);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private void runRejectQueryCountTest(String descFormat, String expnMsg) {
-        AggregateQuery<AggregateCount> query = mock(AggregateQuery.class);
-        ArgumentCaptor<Category> captor = ArgumentCaptor.forClass(Category.class);
-        when(storage.createAggregateQuery(eq(AggregateFunction.COUNT), captor.capture())).thenReturn(query);
-        // first adapt from the target category in order to be able to produce the
-        // right aggregate query with a different result type.
-        CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(AgentInfoDAO.CATEGORY);
-        Category<AggregateCount> aggregateCategory = adapter.getAdapted(AggregateCount.class);
-        String descrString = String.format(descFormat, aggregateCategory.getName());
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(aggregateCategory, descrString);
-        BasicDescriptorParser<AggregateCount> parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("shouldn't have parsed correctly");
-        } catch (DescriptorParsingException e) {
-            assertTrue(e.getMessage().contains(expnMsg));
-        }
-    }
-    
-    
-    /*
-     * At this point list types don't make sense in WHERE.
-     *   What should "'a' != [ 'a', 'b' ]" evaluate to?
-     *   How about this? "'key' > [ 1, 2 ]"
-     * 
-     * The only reasonable use case in WHERE would be 'a' IN [ 'a', 'b' ... ].
-     * We don't support this in a prepared context at this point. Should this
-     * change in future, this test needs to be carefully re-crafted. 
-     */
-    @SuppressWarnings("unchecked")
-    @Test
-    public void rejectListTypesAsFreeVarInInvalidContext() throws DescriptorParsingException {
-        List<String> illegalDescs = new ArrayList<>();
-
-        // Where should not support list types/Pojos.
-        String[] illegalWheres = new String[] {
-                " WHERE 'a' = ?s[",
-                " WHERE 'a' = ?i[",
-                " WHERE 'a' = ?p[",
-                " WHERE 'a' = ?d[",
-        };
-        
-        // Make sure we test for QUERY, QUERY-COUNT, QUERY-DISTINCT, REPLACE, UPDATE, REMOVE
-        // i.e. all that accept a WHERE.
-        String basicQuery = "QUERY " + AgentInfoDAO.CATEGORY.getName();
-        String basicQueryCount = "QUERY-COUNT " + AgentInfoDAO.CATEGORY.getName();
-        String basicQueryDistinct = "QUERY-DISTINCT(foo) " + AgentInfoDAO.CATEGORY.getName();
-        when(storage.createAggregateQuery(eq(AggregateFunction.COUNT), eq(AgentInfoDAO.CATEGORY))).thenReturn(mock(AggregateQuery.class));
-        when(storage.createAggregateQuery(eq(AggregateFunction.DISTINCT), eq(AgentInfoDAO.CATEGORY))).thenReturn(mock(AggregateQuery.class));
-        // note SET clause is legal
-        String basicUpdate = "UPDATE " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?s[";
-        // note SET clause is legal
-        String basicReplace = "REPLACE " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?i[";
-        String basicRemove = "REMOVE " + AgentInfoDAO.CATEGORY.getName();
-        for (String where: illegalWheres) {
-            illegalDescs.add(basicQuery + where);
-            illegalDescs.add(basicQueryCount + where);
-            illegalDescs.add(basicQueryDistinct + where);
-            illegalDescs.add(basicUpdate + where);
-            illegalDescs.add(basicReplace + where);
-            illegalDescs.add(basicRemove + where);
-        }
-        
-        // Test all illegal descs involving WHERE
-        doIllegalDescsTest(illegalDescs, "WHERE", "List");
-        
-        // Test limit too
-        illegalDescs.clear();
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?i[");
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?s[");
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?p[");
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?d[");
-        
-        doIllegalDescsTest(illegalDescs, "LIMIT", "List");
-        
-        // Test sort
-        illegalDescs.clear();
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT ?i[ ASC");
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT ?s[ ASC");
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT ?p[ ASC");
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT ?d[ ASC");
-        
-        doIllegalDescsTest(illegalDescs, "SORT", "List");
-    }
-    
-    /*
-     * Pojos don't make sense in a WHERE, LIMIT and SORT clause. This test makes
-     * sure we reject this right away.
-     * 
-     */
-    @Test
-    public void rejectPojoTypesAsFreeVarInInvalidContext() throws DescriptorParsingException {
-        List<String> illegalDescs = new ArrayList<>();
-        
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?p");
-        doIllegalDescsTest(illegalDescs, "WHERE", "Pojo");
-        illegalDescs.clear();
-        
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?p");
-        doIllegalDescsTest(illegalDescs, "LIMIT", "Pojo");
-        illegalDescs.clear();
-        
-        illegalDescs.add("QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT ?p DSC");
-        doIllegalDescsTest(illegalDescs, "SORT", "Pojo");
-    }
-    
-    private void doIllegalDescsTest(List<String> descs, String errorMsgContext, String type) {
-        for (String strDesc : descs) {
-            StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-            parser = new BasicDescriptorParser<>(storage, desc);
-            try {
-                parser.parse();
-                fail(strDesc + " should not parse");
-            } catch (DescriptorParsingException e) {
-                // pass
-                assertEquals(strDesc + " did not provide correct error message.",
-                        type + " free variable type not allowed in " + errorMsgContext + " context", e.getMessage());
-            }
-        }
-    }
-    
-    @Test
-    public void rejectIllegalFreeParamType() throws DescriptorParsingException {
-        // ? should be one of '?i', '?l', '?s', '?b', '?s['
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE ? < 1";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertEquals("Unknown type of free parameter: '?'", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void rejectParseQueryWhereAndSortMultipleIllegalSortModifier() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'somekey' < 2 AND 'c' = ?s OR 'a' >= ?i SORT 'a' ASC , 'b' ILLEGAL , 'c' ASC";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Expected ASC or DSC"));
-        }
-    }
-
-    @Test
-    public void rejectParseQueryWhereBoolTerm() throws DescriptorParsingException {
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE true AND false";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void rejectQueryWithParenthesis() throws DescriptorParsingException {
-        // We don't allow parenthesized expressions. This is due to mongodb not
-        // allowing this.
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE NOT ( 'a' = 'b' AND 'c' = 'd' )";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-        }
-    }
-
-    @Test
-    public void rejectSimpleQueryWithMissingSpaces() throws DescriptorParsingException {
-        // we require a space before every operator/keyword
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY + " WHERE " + "'a'='b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void rejectSimpleQueryWithMissingSpaces2() throws DescriptorParsingException {
-        // we require a space before every operator/keyword
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY + " WHERE " + "'a' ='b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void rejectSimpleQueryWithInvalidComparison() throws DescriptorParsingException {
-        // <> is illegal
-        String descrString = "QUERY " + AgentInfoDAO.CATEGORY + " WHERE " + "'a' <> 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void rejectInvalidDescriptorStringBadWhere() throws DescriptorParsingException {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " where '" + Key.AGENT_ID.getName() + "'= ?s";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("lower case where not allowed in descriptor. Should have rejected.");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Unexpected token: 'where'"));
-        }
-    }
-    
-    @Test
-    public void rejectInvalidDescriptorStringBadStatementType() throws DescriptorParsingException {
-        String descString = "UNKNOWN some-unknown-category WHERE 1 = ?i";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("UNKNOWN not a valid statement type");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Unknown statement type"));
-        }
-    }
-    
-    @Test
-    public void rejectInvalidDescriptorStringCategoryMismatch() throws DescriptorParsingException {
-        String descString = "QUERY some-unknown-category WHERE 1 = ?i";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("category names in descriptor and Category object did not match!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Category mismatch"));
-        }
-    }
-    
-    @Test
-    public void rejectInvalidDescriptorStringBadSortNoArg() throws DescriptorParsingException {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?i SORT";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("category names in descriptor and Category object did not match!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Invalid where clause"));
-        }
-    }
-    
-    @Test
-    public void rejectInvalidDescriptorStringBadWhereNoArg() throws DescriptorParsingException {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE SORT";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("category names in descriptor and Category object did not match!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("SORT"));
-            assertTrue(e.getMessage().contains("Expected string value"));
-        }
-    }
-    
-    @Test
-    public void rejectAddWithInvalidSetList() throws DescriptorParsingException {
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = , 'c' = 'd'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("Invalid SET values list.");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertEquals("Illegal terminal type. Token was ->,<-", e.getMessage());
-        }
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testCompatibilityNonAggregateQuery() throws DescriptorParsingException {
-        when(storage.createAggregateQuery(any(AggregateFunction.class), any(Category.class))).thenReturn(mock(AggregateQuery.class));
-        String descString = "QUERY-COUNT(foo) " + AgentInfoDAO.CATEGORY.getName();
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new BasicDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            // pass
-        } catch (Exception e) {
-            e.printStackTrace();
-            fail("Expected to parse even though createAggregateQuery returned a simple Query instance instead of AggregateQuery");
-        }
-    }
-    
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/DescriptorParserImplFactory.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-import com.redhat.thermostat.storage.core.BackingStorage;
-import com.redhat.thermostat.storage.core.Category;
-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.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/*
- * NOTE class copied from storage-test-utils for internal testing of Statement
- * Adapters
- */
-class DescriptorParserImplFactory {
-    
-    <T extends Pojo> StatementDescriptorParser<T> getParser(ParserType type, StatementDescriptor<T> desc) {
-        switch (type) {
-        case BASIC:
-            return new BasicDescriptorParser<>(getBasicBackingStorage(), desc);
-        case SEMANTIC:
-            return new SemanticsEnabledDescriptorParser<>(getSemanticBackingStorage(), desc);
-        default:
-            throw new IllegalStateException("Not implemented");
-        }
-    }
-    
-    private BackingStorage getBasicBackingStorage() {
-        return mock(BackingStorage.class);
-    }
-    
-    @SuppressWarnings("unchecked")
-    private BackingStorage getSemanticBackingStorage() {
-        BackingStorage storage = mock(BackingStorage.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(mock(Add.class));
-        when(storage.createUpdate(any(Category.class))).thenReturn(mock(Update.class));
-        when(storage.createRemove(any(Category.class))).thenReturn(mock(Remove.class));
-        when(storage.createReplace(any(Category.class))).thenReturn(mock(Replace.class));
-        when(storage.createQuery(any(Category.class))).thenReturn(mock(Query.class));
-        when(storage.createAggregateQuery(any(AggregateFunction.class), any(Category.class))).thenReturn(mock(AggregateQuery.class));
-        return storage;
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/LimitExpressionTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-
-public class LimitExpressionTest {
-    
-    private LimitExpression expn;
-    
-    @Before
-    public void setup() {
-        expn = new LimitExpression();
-        UnfinishedLimitValue unfinished = new UnfinishedLimitValue();
-        unfinished.setParameterIndex(0);
-        expn.setValue(unfinished);
-    }
-
-    @Test
-    public void canPatchWithInt() {
-        PreparedParameter p = new PreparedParameter();
-        p.setType(int.class);
-        p.setValue(3);
-        
-        PatchedLimitExpression pLimit = null;
-        try {
-            pLimit = expn.patch(new PreparedParameter[] { p });
-            // pass
-        } catch (IllegalPatchException e) {
-            fail(e.getMessage());
-        }
-        assertNotNull(pLimit);
-        assertEquals(3, pLimit.getLimitValue());
-    }
-    
-    @Test
-    public void rejectPatchWithIntList() {
-        PreparedParameter p = new PreparedParameter();
-        p.setType(int[].class);
-        p.setValue(new int[] { 3 });
-        
-        try {
-            expn.patch(new PreparedParameter[] { p });
-            fail("Should not be able to patch with int list");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Invalid parameter type for limit expression."));
-        }
-    }
-    
-    @Test
-    public void rejectPatchWithString() {
-        PreparedParameter p = new PreparedParameter();
-        p.setType(String.class);
-        p.setValue("foo");
-        
-        try {
-            expn.patch(new PreparedParameter[] { p });
-            fail("Should not be able to patch with wrong type");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Invalid parameter type for limit expression."));
-        }
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImplTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,967 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.Pair;
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DataModifyingStatement;
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
-import com.redhat.thermostat.storage.core.Replace;
-import com.redhat.thermostat.storage.core.Statement;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryComparisonExpression;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.storage.query.LiteralExpression;
-
-public class ParsedStatementImplTest {
-
-    private Query<Pojo> statement;
-    
-    @Before
-    public void setup() {
-        statement = new TestQuery();
-    }
-    
-    @After
-    public void tearDown() {
-        statement = null;
-    }
-    
-    @Test
-    public void patchingDuplicatesStatement() throws IllegalPatchException {
-        @SuppressWarnings("unchecked")
-        Statement<Pojo> stmt = (Statement<Pojo>)mock(Statement.class);
-        @SuppressWarnings("unchecked")
-        Statement<Pojo> mock2 = mock(Statement.class);
-        when(stmt.getRawDuplicate()).thenReturn(mock2);
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        parsedStmt.setSetList(new SetList());
-        parsedStmt.setSuffixExpression(suffixExpn);
-        
-        Statement<Pojo> result = parsedStmt.patchStatement(new PreparedParameter[] {});
-        assertNotSame("Statement should get duplicated on patching", stmt, result);
-        assertSame(mock2, result);
-    }
-    
-    @Test
-    public void canPatchWhereAndExpr() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        parsedStmt.setSetList(new SetList());
-        // WHERE a = ? AND c = ?
-        WhereExpression expn = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(expn.getRoot());
-        expn.getRoot().setValue(and);
-        and.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode leftEqual = new BinaryExpressionNode(and);
-        BinaryExpressionNode rightEqual = new BinaryExpressionNode(and);
-        leftEqual.setOperator(BinaryComparisonOperator.EQUALS);
-        rightEqual.setOperator(BinaryComparisonOperator.EQUALS);
-        and.setLeftChild(leftEqual);
-        and.setRightChild(rightEqual);
-        TerminalNode a = new TerminalNode(leftEqual);
-        Key<String> aKey = new Key<>("a");
-        a.setValue(aKey);
-        TerminalNode b = new TerminalNode(leftEqual);
-        UnfinishedValueNode patchB = new UnfinishedValueNode();
-        patchB.setParameterIndex(0);
-        patchB.setType(String.class);
-        b.setValue(patchB);
-        leftEqual.setLeftChild(a);
-        leftEqual.setRightChild(b);
-        TerminalNode c = new TerminalNode(rightEqual);
-        c.setValue("c");
-        rightEqual.setLeftChild(c);
-        TerminalNode d = new TerminalNode(rightEqual);
-        UnfinishedValueNode dPatch = new UnfinishedValueNode();
-        dPatch.setParameterIndex(1);
-        dPatch.setType(int.class);
-        d.setValue(dPatch);
-        rightEqual.setRightChild(d);
-        suffixExpn.setWhereExpn(expn);
-        parsedStmt.setNumFreeParams(1);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        // next, create the PreparedStatement we are going to use for
-        // patching.
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setString(0, "test1");
-        preparedStatement.setInt(1, 2);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Query<Pojo> query = (Query<Pojo>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        TestQuery q = (TestQuery)query;
-        Expression expectedExpression = q.expr;
-        assertTrue(expectedExpression instanceof BinaryLogicalExpression);
-        BinaryLogicalExpression<?, ?> andFinal = (BinaryLogicalExpression<?, ?>) expectedExpression;
-        assertEquals(BinaryLogicalOperator.AND, andFinal.getOperator());
-        assertTrue(andFinal.getLeftOperand() instanceof BinaryComparisonExpression);
-        assertTrue(andFinal.getRightOperand() instanceof BinaryComparisonExpression);
-        BinaryComparisonExpression<?> left = (BinaryComparisonExpression<?>)andFinal.getLeftOperand();
-        BinaryComparisonExpression<?> right = (BinaryComparisonExpression<?>)andFinal.getRightOperand();
-        assertEquals(BinaryComparisonOperator.EQUALS, left.getOperator());
-        assertEquals(BinaryComparisonOperator.EQUALS, right.getOperator());
-        assertTrue(left.getLeftOperand() instanceof LiteralExpression);
-        assertTrue(left.getRightOperand() instanceof LiteralExpression);
-        LiteralExpression<?> leftLiteral1 = (LiteralExpression<?>)left.getLeftOperand();
-        LiteralExpression<?> rightLiteral1 = (LiteralExpression<?>)left.getRightOperand();
-        assertEquals(aKey, leftLiteral1.getValue());
-        assertEquals("test1", rightLiteral1.getValue());
-        LiteralExpression<?> leftLiteral2 = (LiteralExpression<?>)right.getLeftOperand();
-        LiteralExpression<?> rightLiteral2 = (LiteralExpression<?>)right.getRightOperand();
-        assertEquals("c", leftLiteral2.getValue());
-        // right literal value should have been patched to a "d"
-        assertEquals(2, rightLiteral2.getValue());
-    }
-    
-    @Test
-    public void canPatchBasicWhereEquals() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        parsedStmt.setSetList(new SetList());
-        // WHERE a = ?
-        WhereExpression expn = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(expn.getRoot());
-        expn.getRoot().setValue(and);
-        and.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(and);
-        a.setValue(new Key<>("a"));
-        TerminalNode b = new TerminalNode(and);
-        UnfinishedValueNode bPatch = new UnfinishedValueNode();
-        bPatch.setParameterIndex(0);
-        bPatch.setType(boolean.class);
-        b.setValue(bPatch);
-        and.setLeftChild(a);
-        and.setRightChild(b);
-        suffixExpn.setWhereExpn(expn);
-        parsedStmt.setNumFreeParams(1);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        // next, create the PreparedStatement we are going to use for
-        // patching.
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
-        preparedStatement.setBoolean(0, true);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Query<?> query = (Query<?>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        TestQuery q = (TestQuery)query;
-        Expression expectedExpression = q.expr;
-        assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        BinaryComparisonExpression<?> root = (BinaryComparisonExpression<?>)expectedExpression;
-        assertEquals(BinaryComparisonOperator.EQUALS, root.getOperator());
-        assertTrue(root.getLeftOperand() instanceof LiteralExpression);
-        assertTrue(root.getRightOperand() instanceof LiteralExpression);
-        LiteralExpression<?> leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
-        LiteralExpression<?> rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
-        assertEquals(new Key<>("a"), leftLiteral1.getValue());
-        // this should have gotten patched to a "b"
-        assertEquals(true, rightLiteral1.getValue());
-        // now do it again with a different value
-        preparedStatement = new PreparedStatementImpl<>(1);
-        preparedStatement.setBoolean(0, false);
-        params = preparedStatement.getParams();
-        query = (Query<?>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        q = (TestQuery)query;
-        expectedExpression = q.expr;
-        assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        root = (BinaryComparisonExpression<?>)expectedExpression;
-        assertEquals(BinaryComparisonOperator.EQUALS, root.getOperator());
-        assertTrue(root.getLeftOperand() instanceof LiteralExpression);
-        assertTrue(root.getRightOperand() instanceof LiteralExpression);
-        leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
-        rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
-        assertEquals(new Key<>("a"), leftLiteral1.getValue());
-        assertEquals(false, rightLiteral1.getValue());
-    }
-    
-    @Test
-    public void canPatchBasicWhereEqualsLHSKeyAndRHSValue() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        parsedStmt.setSetList(new SetList());
-        // WHERE ?s = ?b
-        WhereExpression expn = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(expn.getRoot());
-        expn.getRoot().setValue(and);
-        and.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(and);
-        UnfinishedValueNode aPatch = new UnfinishedValueNode();
-        aPatch.setLHS(true);
-        aPatch.setType(String.class);
-        aPatch.setParameterIndex(0);
-        a.setValue(aPatch);
-        TerminalNode b = new TerminalNode(and);
-        UnfinishedValueNode bPatch = new UnfinishedValueNode();
-        bPatch.setParameterIndex(1);
-        bPatch.setType(boolean.class);
-        b.setValue(bPatch);
-        and.setLeftChild(a);
-        and.setRightChild(b);
-        suffixExpn.setWhereExpn(expn);
-        parsedStmt.setNumFreeParams(1);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        // next, create the PreparedStatement we are going to use for
-        // patching.
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setString(0, "a");
-        preparedStatement.setBoolean(1, true);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Query<?> query = (Query<?>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        TestQuery q = (TestQuery)query;
-        Expression expectedExpression = q.expr;
-        assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        BinaryComparisonExpression<?> root = (BinaryComparisonExpression<?>)expectedExpression;
-        assertEquals(BinaryComparisonOperator.EQUALS, root.getOperator());
-        assertTrue(root.getLeftOperand() instanceof LiteralExpression);
-        assertTrue(root.getRightOperand() instanceof LiteralExpression);
-        LiteralExpression<?> leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
-        LiteralExpression<?> rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
-        assertEquals(new Key<>("a"), leftLiteral1.getValue());
-        // this should have gotten patched to a "b"
-        assertEquals(true, rightLiteral1.getValue());
-        // now do it again with a different value
-        preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setString(0, "a");
-        preparedStatement.setBoolean(1, false);
-        params = preparedStatement.getParams();
-        query = (Query<?>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        q = (TestQuery)query;
-        expectedExpression = q.expr;
-        assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        root = (BinaryComparisonExpression<?>)expectedExpression;
-        assertEquals(BinaryComparisonOperator.EQUALS, root.getOperator());
-        assertTrue(root.getLeftOperand() instanceof LiteralExpression);
-        assertTrue(root.getRightOperand() instanceof LiteralExpression);
-        leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
-        rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
-        assertEquals(new Key<>("a"), leftLiteral1.getValue());
-        assertEquals(false, rightLiteral1.getValue());
-    }
-    
-    @Test
-    public void canPatchBasicLimit() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        parsedStmt.setSetList(new SetList());
-        SuffixExpression suffixExpn = new SuffixExpression();
-        LimitExpression limitExpnToPatch = new LimitExpression();
-        UnfinishedLimitValue unfinished = new UnfinishedLimitValue();
-        unfinished.setParameterIndex(0);
-        limitExpnToPatch.setValue(unfinished);
-        suffixExpn.setLimitExpn(limitExpnToPatch);
-        suffixExpn.setSortExpn(null);
-        suffixExpn.setWhereExpn(null);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        // set the value for the one unfinished param
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
-        preparedStatement.setInt(0, 3);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Query<?> query = (Query<?>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        TestQuery q = (TestQuery)query;
-        assertEquals(3, q.limitVal);
-    }
-    
-    private SetList buildSetList() {
-        // Build this set list, which corresponds to the TestPojo below
-        // SET 'writerId' = ?s , 'fooTimeStamp' = ?l
-        SetList setList = new SetList();
-        SetListValue writerId = new SetListValue();
-        TerminalNode writerKey = new TerminalNode(null);
-        writerKey.setValue(new Key<>("writerId"));
-        TerminalNode writerValue = new TerminalNode(null);
-        UnfinishedValueNode unfinishedWriter = new UnfinishedValueNode();
-        unfinishedWriter.setParameterIndex(0);
-        unfinishedWriter.setType(String.class);
-        unfinishedWriter.setLHS(false);
-        writerValue.setValue(unfinishedWriter);
-        writerId.setKey(writerKey);
-        writerId.setValue(writerValue);
-        setList.addValue(writerId);
-        SetListValue fooTimeStamp = new SetListValue();
-        TerminalNode timeStampKey = new TerminalNode(null);
-        timeStampKey.setValue(new Key<>("fooTimeStamp"));
-        fooTimeStamp.setKey(timeStampKey);
-        TerminalNode timeStampVal = new TerminalNode(null);
-        UnfinishedValueNode timeStampUnfinished = new UnfinishedValueNode();
-        timeStampUnfinished.setLHS(false);
-        timeStampUnfinished.setParameterIndex(1);
-        timeStampUnfinished.setType(long.class);
-        timeStampVal.setValue(timeStampUnfinished);
-        fooTimeStamp.setValue(timeStampVal);
-        setList.addValue(fooTimeStamp);
-        return setList;
-    }
-    
-    /*
-     * Test for patching of:
-     *  "ADD something SET 'writerId' = ?s, 'fooTimeStamp' = ?l"
-     */
-    @Test
-    public void canPatchBasicSetListAdd() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        DataModifyingStatement<TestPojo> stmt = new TestAdd<>();
-        ParsedStatementImpl<TestPojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        SetList setList = buildSetList();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        suffixExpn.setWhereExpn(null);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        assertEquals(2, setList.getValues().size());
-        parsedStmt.setSetList(setList);
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setString(0, "foo-writer");
-        preparedStatement.setLong(1, Long.MAX_VALUE);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Add<TestPojo> add = (Add<TestPojo>)parsedStmt.patchStatement(params);
-        assertTrue(add instanceof TestAdd);
-        TestAdd<TestPojo> q = (TestAdd<TestPojo>)add;
-        Map<String, Object> vals = q.values;
-        assertEquals(2, vals.keySet().size());
-        assertEquals("foo-writer", vals.get("writerId"));
-        assertEquals(Long.MAX_VALUE, vals.get("fooTimeStamp"));
-    }
-    
-    /*
-     * Test for patching of:
-     *  "ADD something SET 'someList' = ?p["
-     */
-    @Test
-    public void canPatchSetListAddWithPojoList() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        DataModifyingStatement<FancyPojo> stmt = new TestAdd<>();
-        ParsedStatementImpl<FancyPojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        SetList setList = new SetList();
-        parsedStmt.setSetList(setList);
-        TerminalNode someProperty = new TerminalNode(null);
-        someProperty.setValue(new Key<>("someList"));
-        TerminalNode somePropertyVal = new TerminalNode(null);
-        UnfinishedValueNode unfinishedPojoList = new UnfinishedValueNode();
-        unfinishedPojoList.setLHS(false);
-        unfinishedPojoList.setType(Pojo[].class);
-        unfinishedPojoList.setParameterIndex(0);
-        somePropertyVal.setValue(unfinishedPojoList);
-        SetListValue value = new SetListValue();
-        value.setKey(someProperty);
-        value.setValue(somePropertyVal);
-        setList.addValue(value);
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        suffixExpn.setWhereExpn(null);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        assertEquals(1, setList.getValues().size());
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
-        TestPojo elem1 = new TestPojo();
-        elem1.setFooTimeStamp(-300);
-        elem1.setWriterId("elem1");
-        TestPojo elem2 = new TestPojo();
-        elem2.setFooTimeStamp(-301);
-        elem2.setWriterId("elem2");
-        TestPojo[] elems = new TestPojo[] {
-                elem1, elem2
-        };
-        preparedStatement.setPojoList(0, elems);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Add<FancyPojo> add = (Add<FancyPojo>)parsedStmt.patchStatement(params);
-        assertTrue(add instanceof TestAdd);
-        TestAdd<FancyPojo> q = (TestAdd<FancyPojo>)add;
-        Map<String, Object> vals = q.values;
-        assertEquals(1, vals.keySet().size());
-        assertEquals(null, vals.get("writerId"));
-        assertNotNull(vals.get("someList"));
-        Object someList = vals.get("someList");
-        assertTrue(someList instanceof TestPojo[]);
-        TestPojo[] tPojo = (TestPojo[])someList;
-        assertEquals(2, tPojo.length);
-        TestPojo first = tPojo[0];
-        TestPojo second = tPojo[1];
-        assertEquals(elem1, first);
-        assertEquals(elem2, second);
-        assertEquals("elem1", first.getWriterId());
-        assertEquals(-300, first.getFooTimeStamp());
-        assertEquals("elem2", second.getWriterId());
-        assertEquals(-301, second.getFooTimeStamp());
-    }
-    
-    /*
-     * Test for patching of:
-     *  "REPLACE something SET ?s = 'foo-bar', 'fooTimeStamp' = ?l WHERE 'foo' = ?i"
-     */
-    @Test
-    public void canPatchBasicSetListReplace() throws IllegalPatchException {
-        DataModifyingStatement<TestPojo> stmt = new TestReplace();
-        ParsedStatementImpl<TestPojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        
-        // Build this set list, which corresponds to the TestPojo below
-        // SET ?s = 'foo-bar' , 'fooTimeStamp' = ?l
-        SetList setList = new SetList();
-        SetListValue writerId = new SetListValue();
-        TerminalNode writerKey = new TerminalNode(null);
-        UnfinishedValueNode unfinishedWriterKey = new UnfinishedValueNode();
-        unfinishedWriterKey.setParameterIndex(0);
-        unfinishedWriterKey.setType(String.class);
-        unfinishedWriterKey.setLHS(true);
-        writerKey.setValue(unfinishedWriterKey);
-        writerId.setKey(writerKey);
-        TerminalNode writerValue = new TerminalNode(null);
-        writerValue.setValue("foo-bar");
-        writerId.setValue(writerValue);
-        setList.addValue(writerId);
-        SetListValue fooTimeStamp = new SetListValue();
-        TerminalNode timeStampKey = new TerminalNode(null);
-        timeStampKey.setValue(new Key<>("fooTimeStamp"));
-        fooTimeStamp.setKey(timeStampKey);
-        TerminalNode timeStampVal = new TerminalNode(null);
-        UnfinishedValueNode timeStampUnfinished = new UnfinishedValueNode();
-        timeStampUnfinished.setLHS(false);
-        timeStampUnfinished.setParameterIndex(1);
-        timeStampUnfinished.setType(long.class);
-        timeStampVal.setValue(timeStampUnfinished);
-        fooTimeStamp.setValue(timeStampVal);
-        setList.addValue(fooTimeStamp);
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        
-        // WHERE 'foo' = ?i
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode equals = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(equals);
-        equals.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode fooPatch = new TerminalNode(equals);
-        UnfinishedValueNode patch2 = new UnfinishedValueNode();
-        patch2.setLHS(false);
-        patch2.setType(int.class);
-        patch2.setParameterIndex(2);
-        fooPatch.setValue(patch2);
-        TerminalNode foo = new TerminalNode(equals);
-        foo.setValue(new Key<>("foo"));
-        equals.setLeftChild(foo);
-        equals.setRightChild(fooPatch);
-        suffixExpn.setWhereExpn(where);
-        
-        parsedStmt.setSuffixExpression(suffixExpn);
-        assertEquals(2, setList.getValues().size());
-        parsedStmt.setSetList(setList);
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(3);
-        preparedStatement.setString(0, "writerId");
-        preparedStatement.setLong(1, Long.MAX_VALUE);
-        preparedStatement.setInt(2, -400);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Replace<TestPojo> replace = (Replace<TestPojo>)parsedStmt.patchStatement(params);
-        assertTrue(replace instanceof TestReplace);
-        TestReplace q = (TestReplace)replace;
-        Map<String, Object> vals = q.values;
-        assertEquals(2, vals.keySet().size());
-        assertEquals("foo-bar", vals.get("writerId"));
-        assertEquals(Long.MAX_VALUE, vals.get("fooTimeStamp"));
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expectedExpression = factory.equalTo(new Key<>("foo"), -400);
-        assertEquals(expectedExpression, q.where);
-    }
-    
-    /*
-     * Test for patching of:
-     *  "UPDATE something SET 'writerId' = ?s WHERE 'foo' = ?i"
-     */
-    @Test
-    public void canPatchBasicSetListUpdate() throws IllegalPatchException {
-        DataModifyingStatement<TestPojo> stmt = new TestUpdate();
-        ParsedStatementImpl<TestPojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        
-        // Build this set list, which corresponds to the TestPojo below
-        // SET 'writerId' = ?s
-        SetList setList = new SetList();
-        SetListValue writerId = new SetListValue();
-        TerminalNode writerKey = new TerminalNode(null);
-        writerKey.setValue(new Key<>("writerId"));
-        TerminalNode writerValue = new TerminalNode(null);
-        UnfinishedValueNode unfinishedWriterValue = new UnfinishedValueNode();
-        unfinishedWriterValue.setParameterIndex(0);
-        unfinishedWriterValue.setType(String.class);
-        unfinishedWriterValue.setLHS(false);
-        writerValue.setValue(unfinishedWriterValue);
-        writerId.setKey(writerKey);
-        writerId.setValue(writerValue);
-        setList.addValue(writerId);
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        
-        // WHERE 'foo' = ?i
-        WhereExpression where = new WhereExpression();
-        BinaryExpressionNode equals = new BinaryExpressionNode(where.getRoot());
-        where.getRoot().setValue(equals);
-        equals.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode fooPatch = new TerminalNode(equals);
-        UnfinishedValueNode patch2 = new UnfinishedValueNode();
-        patch2.setLHS(false);
-        patch2.setType(int.class);
-        patch2.setParameterIndex(1);
-        fooPatch.setValue(patch2);
-        TerminalNode foo = new TerminalNode(equals);
-        foo.setValue(new Key<>("foo"));
-        equals.setLeftChild(foo);
-        equals.setRightChild(fooPatch);
-        suffixExpn.setWhereExpn(where);
-        
-        parsedStmt.setSuffixExpression(suffixExpn);
-        assertEquals(1, setList.getValues().size());
-        parsedStmt.setSetList(setList);
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setString(0, "foobar-writer-id");
-        preparedStatement.setInt(1, -400);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Update<TestPojo> replace = (Update<TestPojo>)parsedStmt.patchStatement(params);
-        assertTrue(replace instanceof TestUpdate);
-        TestUpdate q = (TestUpdate)replace;
-        List<Pair<Object, Object>> updates = q.updates;
-        assertEquals(1, updates.size());
-        Pair<Object, Object> update = updates.get(0);
-        assertEquals("writerId", update.getFirst());
-        assertEquals("foobar-writer-id", update.getSecond());
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expectedExpression = factory.equalTo(new Key<>("foo"), -400);
-        assertEquals(expectedExpression, q.where);
-    }
-    
-    @Test
-    public void canPatchBasicSort() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        parsedStmt.setSetList(new SetList());
-        SuffixExpression suffixExpn = new SuffixExpression();
-        // SORT ? ASC, b DSC
-        SortExpression sortExpn = new SortExpression();
-        SortMember member = new SortMember();
-        member.setDirection(SortDirection.ASCENDING);
-        UnfinishedSortKey unfinished = new UnfinishedSortKey();
-        unfinished.setParameterIndex(0);
-        member.setSortKey(unfinished);
-        SortMember member2 = new SortMember();
-        member2.setDirection(SortDirection.DESCENDING);
-        member2.setSortKey("b");
-        sortExpn.addMember(member);
-        sortExpn.addMember(member2);
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(sortExpn);
-        suffixExpn.setWhereExpn(null);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        // set the value for the one unfinished param
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
-        preparedStatement.setString(0, "a");
-        PreparedParameter[] params = preparedStatement.getParams();
-        // finally test the patching
-        Query<Pojo> query = (Query<Pojo>)parsedStmt.patchStatement(params);
-        assertTrue(query instanceof TestQuery);
-        TestQuery q = (TestQuery)query;
-        List<Pair<Key<?>, SortDirection>> actualSorts = q.sorts;
-        assertEquals(2, actualSorts.size());
-        Pair<Key<?>, SortDirection> first = actualSorts.get(0);
-        Key<?> firstKeyActual = (Key<?>)first.getFirst();
-        Key<?> expectedFirst = new Key<>("a");
-        assertEquals(expectedFirst, firstKeyActual);
-        assertEquals(SortDirection.ASCENDING, first.getSecond());
-        Pair<Key<?>, SortDirection> second = actualSorts.get(1);
-        Key<?> secondKeyActual = (Key<?>)second.getFirst();
-        Key<?> expectedSecond = new Key<>("b");
-        assertEquals(expectedSecond, secondKeyActual);
-        assertEquals(SortDirection.DESCENDING, second.getSecond());
-    }
-    
-    @Test
-    public void failPatchSetListAddWrongType() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        DataModifyingStatement<TestPojo> stmt = new TestAdd<>();
-        ParsedStatementImpl<TestPojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        SetList setList = buildSetList();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        suffixExpn.setWhereExpn(null);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        assertEquals(2, setList.getValues().size());
-        parsedStmt.setSetList(setList);
-        // set the value for the one unfinished param
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setLong(0, -1);
-        preparedStatement.setString(1, "foobar");
-        PreparedParameter[] params = preparedStatement.getParams();
-        // this should fail since types don't match
-        try {
-            parsedStmt.patchStatement(params);
-            fail("Should have failed to patch, due to type mismatch");
-        } catch (IllegalPatchException e) {
-            assertTrue(e.getMessage().contains("Expected " + String.class.getName()));
-            // pass
-        }
-    }
-    
-    @Test
-    public void failPatchSetListAddInsufficientParams() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        DataModifyingStatement<TestPojo> stmt = new TestAdd<>();
-        ParsedStatementImpl<TestPojo> parsedStmt = new ParsedStatementImpl<>(stmt);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        SetList setList = buildSetList();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        suffixExpn.setWhereExpn(null);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        assertEquals(2, setList.getValues().size());
-        parsedStmt.setSetList(setList);
-        // set the value for the one unfinished param
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(0);
-        PreparedParameter[] params = preparedStatement.getParams();
-        // this should fail since types don't match
-        try {
-            parsedStmt.patchStatement(params);
-            fail("Should have failed to patch, due to type mismatch");
-        } catch (IllegalPatchException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void failPatchWithWrongType() throws IllegalPatchException {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        parsedStmt.setSetList(new SetList());
-        SuffixExpression suffixExpn = new SuffixExpression();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        // WHERE 'a' = ?s AND 'c' = ?i
-        WhereExpression expn = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(expn.getRoot());
-        expn.getRoot().setValue(and);
-        and.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode leftEqual = new BinaryExpressionNode(and);
-        BinaryExpressionNode rightEqual = new BinaryExpressionNode(and);
-        leftEqual.setOperator(BinaryComparisonOperator.EQUALS);
-        rightEqual.setOperator(BinaryComparisonOperator.EQUALS);
-        and.setLeftChild(leftEqual);
-        and.setRightChild(rightEqual);
-        TerminalNode a = new TerminalNode(leftEqual);
-        Key<?> aKey = new Key<>("a");
-        a.setValue(aKey);
-        TerminalNode b = new TerminalNode(leftEqual);
-        UnfinishedValueNode patchB = new UnfinishedValueNode();
-        patchB.setType(String.class);
-        patchB.setParameterIndex(0);
-        b.setValue(patchB);
-        leftEqual.setLeftChild(a);
-        leftEqual.setRightChild(b);
-        TerminalNode c = new TerminalNode(rightEqual);
-        Key<?> cKey = new Key<>("c");
-        c.setValue(cKey);
-        rightEqual.setLeftChild(c);
-        TerminalNode d = new TerminalNode(rightEqual);
-        UnfinishedValueNode dPatch = new UnfinishedValueNode();
-        dPatch.setParameterIndex(1);
-        dPatch.setType(Integer.class);
-        d.setValue(dPatch);
-        rightEqual.setRightChild(d);
-        suffixExpn.setWhereExpn(expn);
-        parsedStmt.setNumFreeParams(1);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        // next, create the PreparedStatement we are going to use for
-        // patching.
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setString(0, "test1");
-        preparedStatement.setString(1, "foo");
-        // finally test the patching
-        try {
-            PreparedParameter[] params = preparedStatement.getParams();
-            parsedStmt.patchStatement(params);
-            fail("should have failed to patch param 1 with a string value (expected int)");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("invalid type when attempting to patch"));
-        }
-    }
-    
-    @Test
-    public void failPatchBasicEqualsIfIndexOutofBounds() {
-        // create the parsedStatementImpl we are going to use
-        ParsedStatementImpl<Pojo> parsedStmt = new ParsedStatementImpl<>(statement);
-        SuffixExpression suffixExpn = new SuffixExpression();
-        suffixExpn.setLimitExpn(null);
-        suffixExpn.setSortExpn(null);
-        parsedStmt.setSetList(new SetList());
-        // WHERE a = ?
-        WhereExpression expn = new WhereExpression();
-        BinaryExpressionNode and = new BinaryExpressionNode(expn.getRoot());
-        expn.getRoot().setValue(and);
-        and.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode a = new TerminalNode(and);
-        a.setValue("a");
-        TerminalNode b = new TerminalNode(and);
-        UnfinishedValueNode bPatch = new UnfinishedValueNode();
-        bPatch.setParameterIndex(1); // out of bounds
-        b.setValue(bPatch);
-        and.setLeftChild(a);
-        and.setRightChild(b);
-        suffixExpn.setWhereExpn(expn);
-        parsedStmt.setNumFreeParams(1);
-        parsedStmt.setSuffixExpression(suffixExpn);
-        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
-        preparedStatement.setString(0, "b");
-        try {
-            PreparedParameter[] params = preparedStatement.getParams();
-            // this should fail
-            parsedStmt.patchStatement(params);
-            fail("should not reach here");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getCause() instanceof ArrayIndexOutOfBoundsException);
-        }
-    }
-    
-    private static class TestQuery implements Query<Pojo> {
-
-        private Expression expr;
-        private List<Pair<Key<?>, SortDirection>> sorts;
-        private int limitVal = -1;
-        
-        private TestQuery() {
-            sorts = new ArrayList<>();
-        }
-        
-        @Override
-        public void where(Expression expr) {
-            this.expr = expr;
-        }
-
-        @Override
-        public void sort(Key<?> key, SortDirection direction) {
-            Pair<Key<?>, SortDirection> sortPair = new Pair<Key<?>, SortDirection>(key, direction);
-            sorts.add(sortPair);
-        }
-
-        @Override
-        public void limit(int n) {
-            this.limitVal = n;
-        }
-
-        @Override
-        public Cursor<Pojo> execute() {
-            // Not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public Expression getWhereExpression() {
-            // Not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public Statement<Pojo> getRawDuplicate() {
-            return new TestQuery();
-        }
-        
-    }
-    
-    private static class TestAdd<T extends Pojo> implements Add<T> {
-        
-        private Map<String, Object> values = new HashMap<>();
-
-        @Override
-        public void set(String key, Object value) {
-            values.put(key, value);
-        }
-
-        @Override
-        public int apply() {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public Statement<T> getRawDuplicate() {
-            return new TestAdd<>();
-        }
-        
-    }
-    
-    private static class TestReplace implements Replace<TestPojo> {
-
-        private Expression where;
-        private Map<String, Object> values = new HashMap<>();
-        
-        @Override
-        public void set(String key, Object value) {
-            values.put(key, value);
-        }
-
-        @Override
-        public void where(Expression expression) {
-            where = expression;
-        }
-
-        @Override
-        public int apply() {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public Statement<TestPojo> getRawDuplicate() {
-            return new TestReplace();
-        }
-        
-    }
-    
-    private static class TestUpdate implements Update<TestPojo> {
-
-        private Expression where;
-        private List<Pair<Object, Object>> updates = new ArrayList<>();
-        
-        @Override
-        public void where(Expression expr) {
-            this.where = expr;
-        }
-
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        @Override
-        public void set(String key, Object value) {
-            Pair update = new Pair<>(key, value);
-            updates.add(update);
-        }
-
-        @Override
-        public int apply() {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public Statement<TestPojo> getRawDuplicate() {
-            return new TestUpdate();
-        }
-        
-    }
-    
-    public static class TestPojo implements Pojo {
-        
-        private String writerId;
-        private long fooTimeStamp;
-        
-        public String getWriterId() {
-            return writerId;
-        }
-        public void setWriterId(String writerId) {
-            this.writerId = writerId;
-        }
-        public long getFooTimeStamp() {
-            return fooTimeStamp;
-        }
-        public void setFooTimeStamp(long fooTimeStamp) {
-            this.fooTimeStamp = fooTimeStamp;
-        }
-        
-    }
-    
-    public static class FancyPojo extends TestPojo {
-        
-        private TestPojo[] someList;
-
-        public TestPojo[] getSomeList() {
-            return someList;
-        }
-
-        public void setSomeList(TestPojo[] someList) {
-            this.someList = someList;
-        }
-        
-        
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParserType.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-/*
- * NOTE class copied from storage-test-utils for internal testing
- */
-public enum ParserType {
-    BASIC,
-    SEMANTIC
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImplTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,480 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.Pair;
-import com.redhat.thermostat.storage.core.Add;
-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.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.Statement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryComparisonExpression;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.LiteralExpression;
-
-public class PreparedStatementImplTest {
-    
-    private static int counter = 0;
-    
-    /*
-     * Category names need to be unique. In order to prevent IllegalStateExceptions
-     * create a new category name each time this is called.
-     */
-    private synchronized String getNextCategoryName() {
-        String name = "foo-table-" + counter;
-        counter++;
-        return name;
-    }
-    
-    @Test
-    public void failToSetIndexOutOfBounds() {
-        PreparedStatementImpl<?> preparedStatement = new PreparedStatementImpl<>(2);
-        preparedStatement.setInt(1, 3);
-        preparedStatement.setString(0, "testing");
-        try {
-            preparedStatement.setLong(3, 1);
-            fail("should have thrown exception");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-        try {
-            preparedStatement.setInt(4, 1);
-            fail("should have thrown exception");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-        try {
-            preparedStatement.setString(10, "ignored");
-            fail("should have thrown exception");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-        try {
-            preparedStatement.setStringList(3, new String[] { "ignored" });
-            fail("should have thrown exception");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void canDoParsingPatchingAndExecutionQuery() throws Exception {
-        String categoryName = getNextCategoryName();
-        String queryString = "QUERY " + categoryName + " WHERE 'a' = ?s";
-        Category<FooPojo> fooCategory = new Category<>(categoryName, FooPojo.class, new Key<String>("a"));
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(fooCategory, queryString);
-        BackingStorage storage = mock(BackingStorage.class);
-        StubQuery<FooPojo> stmt = new StubQuery<>();
-        when(storage.createQuery(fooCategory)).thenReturn(stmt);
-        PreparedStatementImpl<FooPojo> preparedStatement = new PreparedStatementImpl<>(storage, desc);
-        preparedStatement.setString(0, "foo");
-        preparedStatement.executeQuery();
-        assertTrue(stmt.called);
-        LiteralExpression<Key<String>> o1 = new LiteralExpression<>(new Key<String>("a"));
-        LiteralExpression<String> o2 = new LiteralExpression<>("foo"); 
-        BinaryComparisonExpression<String> binComp = new BinaryComparisonExpression<>(
-                o1, BinaryComparisonOperator.EQUALS, o2);
-        assertEquals(binComp, stmt.expr);
-    }
-    
-    @Test
-    public void canDoParsingPatchingAndExecutionForAdd() throws Exception {
-        String categoryName = getNextCategoryName();
-        String addString = "ADD " + categoryName +" SET 'foo' = ?s";
-        Category<FooPojo> fooCategory = new Category<>(categoryName, FooPojo.class, new Key<String>("foo"));
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(fooCategory, addString);
-        BackingStorage storage = mock(BackingStorage.class);
-        TestAdd<FooPojo> add = new TestAdd<>();
-        when(storage.createAdd(fooCategory)).thenReturn(add);
-        PreparedStatement<FooPojo> preparedStatement = new PreparedStatementImpl<FooPojo>(storage, desc);
-        preparedStatement.setString(0, "foo-val");
-        assertFalse(add.executed);
-        try {
-            // this should call add.apply();
-            preparedStatement.execute();
-        } catch (StatementExecutionException e) {
-            fail(e.getMessage());
-        }
-        assertFalse(add.values.isEmpty());
-        assertTrue(add.executed);
-        assertEquals(1, add.values.keySet().size());
-        assertEquals("foo-val", add.values.get("foo"));
-    }
-    
-    @Test
-    public void canDoParsingPatchingAndExecutionForAddInvolvingFancyPojo() throws Exception {
-        String categoryName = getNextCategoryName();
-        String addString = "ADD " + categoryName + " SET 'fancyFoo' = ?p[";
-        Category<FancyFoo> fooCategory = new Category<>(categoryName, FancyFoo.class, new Key<String>("fancyFoo"));
-        StatementDescriptor<FancyFoo> desc = new StatementDescriptor<>(fooCategory, addString);
-        BackingStorage storage = mock(BackingStorage.class);
-        TestAdd<FancyFoo> add = new TestAdd<>();
-        when(storage.createAdd(fooCategory)).thenReturn(add);
-        PreparedStatement<FancyFoo> preparedStatement = new PreparedStatementImpl<FancyFoo>(storage, desc);
-        FooPojo one = new FooPojo();
-        one.setFoo("one");
-        FooPojo two = new FooPojo();
-        two.setFoo("two");
-        FooPojo[] list = new FooPojo[] {
-                one, two
-        };
-        preparedStatement.setPojoList(0, list);
-        assertFalse(add.executed);
-        try {
-            // this should call add.apply();
-            preparedStatement.execute();
-        } catch (StatementExecutionException e) {
-            fail(e.getMessage());
-        }
-        assertFalse(add.values.isEmpty());
-        assertEquals(1, add.values.keySet().size());
-        assertTrue(add.executed);
-        FooPojo[] fancyFoo = (FooPojo[])add.values.get("fancyFoo");
-        assertEquals(2, fancyFoo.length);
-        FooPojo first = fancyFoo[0];
-        FooPojo second = fancyFoo[1];
-        assertEquals("one", first.getFoo());
-        assertEquals("two", second.getFoo());
-    }
-    
-    @Test
-    public void canDoParsingPatchingAndExecutionForUpdate() throws Exception {
-        String categoryName = getNextCategoryName();
-        String addString = "UPDATE " + categoryName + " SET 'foo' = ?s WHERE 'foo' = ?s";
-        Category<FooPojo> fooCategory = new Category<>(categoryName, FooPojo.class, new Key<String>("foo"));
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(fooCategory, addString);
-        BackingStorage storage = mock(BackingStorage.class);
-        TestUpdate update = new TestUpdate();
-        when(storage.createUpdate(fooCategory)).thenReturn(update);
-        PreparedStatement<FooPojo> preparedStatement = new PreparedStatementImpl<FooPojo>(storage, desc);
-        preparedStatement.setString(0, "foo-val");
-        preparedStatement.setString(1, "nice");
-        assertFalse(update.executed);
-        try {
-            // this should call apply();
-            preparedStatement.execute();
-        } catch (StatementExecutionException e) {
-            fail(e.getMessage());
-        }
-        assertTrue(update.executed);
-        assertEquals(1, update.updates.size());
-        Pair<String, Object> item = update.updates.get(0);
-        assertEquals("foo", item.getFirst());
-        assertEquals("foo-val", item.getSecond());
-        LiteralExpression<Key<String>> o1 = new LiteralExpression<>(new Key<String>("foo"));
-        LiteralExpression<String> o2 = new LiteralExpression<>("nice"); 
-        BinaryComparisonExpression<String> binComp = new BinaryComparisonExpression<>(
-                o1, BinaryComparisonOperator.EQUALS, o2);
-        assertEquals(binComp, update.where);
-    }
-    
-    @Test
-    public void canDoParsingPatchingAndExecutionForReplace() throws Exception {
-        String categoryName = getNextCategoryName();
-        String addString = "REPLACE " + categoryName + " SET 'foo' = ?s WHERE 'foo' = ?s";
-        Category<FooPojo> fooCategory = new Category<>(categoryName, FooPojo.class, new Key<String>("foo"));
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(fooCategory, addString);
-        BackingStorage storage = mock(BackingStorage.class);
-        TestReplace<FooPojo> replace = new TestReplace<>();
-        when(storage.createReplace(fooCategory)).thenReturn(replace);
-        PreparedStatement<FooPojo> preparedStatement = new PreparedStatementImpl<FooPojo>(storage, desc);
-        preparedStatement.setString(0, "foo-val");
-        preparedStatement.setString(1, "bar");
-        assertFalse(replace.executed);
-        try {
-            // this should call apply();
-            preparedStatement.execute();
-        } catch (StatementExecutionException e) {
-            fail(e.getMessage());
-        }
-        assertFalse(replace.values.isEmpty());
-        assertTrue(replace.executed);
-        assertEquals("foo-val", replace.values.get("foo"));
-        LiteralExpression<Key<String>> o1 = new LiteralExpression<>(new Key<String>("foo"));
-        LiteralExpression<String> o2 = new LiteralExpression<>("bar"); 
-        BinaryComparisonExpression<String> binComp = new BinaryComparisonExpression<>(
-                o1, BinaryComparisonOperator.EQUALS, o2);
-        assertEquals(binComp, replace.where);
-    }
-    
-    @Test
-    public void canDoParsingPatchingAndExecutionForRemove() throws Exception {
-        String categoryName = getNextCategoryName();
-        String addString = "REMOVE " + categoryName + " WHERE 'fooRem' = ?s";
-        Category<FooPojo> fooCategory = new Category<>(categoryName, FooPojo.class, new Key<String>("foo"));
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(fooCategory, addString);
-        BackingStorage storage = mock(BackingStorage.class);
-        TestRemove<FooPojo> remove = new TestRemove<>();
-        when(storage.createRemove(fooCategory)).thenReturn(remove);
-        PreparedStatement<FooPojo> preparedStatement = new PreparedStatementImpl<FooPojo>(storage, desc);
-        preparedStatement.setString(0, "bar");
-        assertFalse(remove.executed);
-        try {
-            // this should call apply();
-            preparedStatement.execute();
-        } catch (StatementExecutionException e) {
-            fail(e.getMessage());
-        }
-        assertTrue(remove.executed);
-        LiteralExpression<Key<String>> o1 = new LiteralExpression<>(new Key<String>("fooRem"));
-        LiteralExpression<String> o2 = new LiteralExpression<>("bar"); 
-        BinaryComparisonExpression<String> binComp = new BinaryComparisonExpression<>(
-                o1, BinaryComparisonOperator.EQUALS, o2);
-        assertEquals(binComp, remove.where);
-    }
-    
-    @Test
-    public void failExecutionWithWronglyTypedParams() throws Exception {
-        String categoryName = getNextCategoryName();
-        String queryString = "QUERY " + categoryName + " WHERE 'a' = ?b";
-        Category<FooPojo> fooCategory = new Category<>(categoryName, FooPojo.class, new Key<String>("a"));
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(fooCategory, queryString);
-        BackingStorage storage = mock(BackingStorage.class);
-        StubQuery<FooPojo> stmt = new StubQuery<>();
-        when(storage.createQuery(fooCategory)).thenReturn(stmt);
-        PreparedStatementImpl<FooPojo> preparedStatement = new PreparedStatementImpl<>(storage, desc);
-        preparedStatement.setString(0, "foo");
-        try {
-            preparedStatement.executeQuery();
-            fail("Should have thrown SEE due to type mismatch. boolean vs. string");
-        } catch (StatementExecutionException e) {
-            // pass
-            assertTrue(e.getMessage().contains("invalid type when attempting to patch"));
-        }
-    }
-    
-    private static class TestAdd<T extends Pojo> implements Add<T> {
-
-        private Map<String, Object> values = new HashMap<>();
-        private boolean executed = false;
-        
-        @Override
-        public void set(String key, Object value) {
-            values.put(key, value);
-        }
-
-        @Override
-        public int apply() {
-            executed = true;
-            return 0;
-        }
-
-        @Override
-        public Statement<T> getRawDuplicate() {
-            // we don't duplicate for this test
-            return this;
-        }
-
-    }
-    
-    private static class TestReplace<T extends Pojo> implements Replace<T> {
-
-        private Map<String, Object> values = new HashMap<>();
-        private boolean executed = false;
-        private Expression where;
-        
-        @Override
-        public void set(String key, Object value) {
-            values.put(key, value);
-        }
-
-        @Override
-        public void where(Expression expression) {
-            this.where = expression;
-        }
-
-        @Override
-        public int apply() {
-            this.executed = true;
-            return 0;
-        }
-
-        @Override
-        public Statement<T> getRawDuplicate() {
-            // we don't duplicate for this test
-            return this;
-        }
-        
-    }
-    
-    private static class TestUpdate implements Update<FooPojo> {
-
-        private Expression where;
-        private List<Pair<String, Object>> updates = new ArrayList<>();
-        private boolean executed = false;
-        
-        @Override
-        public void where(Expression expr) {
-            this.where = expr;
-        }
-
-        @Override
-        public void set(String key, Object value) {
-            Pair<String, Object> item = new Pair<>(key, value);
-            updates.add(item);
-        }
-
-        @Override
-        public int apply() {
-            this.executed = true;
-            return 0;
-        }
-
-        @Override
-        public Statement<FooPojo> getRawDuplicate() {
-            // we don't duplicate for this test
-            return this;
-        }
-        
-    }
-    
-    private static class TestRemove<T extends Pojo> implements Remove<T> {
-
-        private Expression where;
-        private boolean executed = false;
-        
-        @Override
-        public void where(Expression where) {
-            this.where = where;
-        }
-
-        @Override
-        public int apply() {
-            this.executed = true;
-            return 0;
-        }
-
-        @Override
-        public Statement<T> getRawDuplicate() {
-            // we don't duplicate for this test
-            return this;
-        }
-        
-    }
-    
-    public static class FooPojo implements Pojo {
-        
-        String foo;
-        
-        public void setFoo(String foo) {
-            this.foo = foo;
-        }
-        
-        public String getFoo() {
-            return this.foo;
-        }
-    }
-    
-    public static class FancyFoo extends FooPojo {
-        
-        private FooPojo[] fancyFoo;
-
-        public FooPojo[] getFancyFoo() {
-            return fancyFoo;
-        }
-
-        public void setFancyFoo(FooPojo[] fancyFoo) {
-            this.fancyFoo = fancyFoo;
-        }
-        
-    }
-    
-    private static class StubQuery<T extends Pojo> implements Query<T> {
-
-        private Expression expr;
-        private boolean called = false;
-        
-        @Override
-        public void where(Expression expr) {
-            this.expr = expr;
-        }
-
-        @Override
-        public void sort(Key<?> key, SortDirection direction) {
-            // nothing
-        }
-
-        @Override
-        public void limit(int n) {
-            // nothing
-        }
-
-        @Override
-        public Cursor<T> execute() {
-            called = true;
-            return null;
-        }
-
-        @Override
-        public Expression getWhereExpression() {
-            // not implemented
-            return null;
-        }
-
-        @Override
-        public Statement<T> getRawDuplicate() {
-            // For this test, we don't duplicate
-            return this;
-        }
-        
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SemanticsEnabledDescriptorParserTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,506 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-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.ParsedStatement;
-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.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class SemanticsEnabledDescriptorParserTest {
-    
-    private static final String COMPLETE_SET_LIST_AGENT_INFO = "SET " +
-            "'" + Key.AGENT_ID.getName() + "' = ?s , " +
-            "'" + AgentInfoDAO.START_TIME_KEY.getName() + "' = ?l , " +
-            "'" + AgentInfoDAO.STOP_TIME_KEY.getName() + "' = ?l , " +
-            "'" + AgentInfoDAO.ALIVE_KEY.getName() + "' = ?b , " +
-            "'" + AgentInfoDAO.CONFIG_LISTEN_ADDRESS.getName() + "' = ?s";
-    
-    private static final String INCOMPLETE_SET_LIST_AGENT_INFO = "SET " +
-            "'" + Key.AGENT_ID.getName() + "' = ?s , " +
-            "'" + AgentInfoDAO.START_TIME_KEY.getName() + "' = ?l , " +
-            // stop-time key missing
-            "'" + AgentInfoDAO.ALIVE_KEY.getName() + "' = ?b , " +
-            "'" + AgentInfoDAO.CONFIG_LISTEN_ADDRESS.getName() + "' = ?s";
-
-    private BackingStorage storage;
-    private Query<AgentInformation> mockQuery;
-    private AggregateQuery<AgentInformation> aggQuery;
-    private SemanticsEnabledDescriptorParser<AgentInformation> parser;
-    private Add<AgentInformation> mockAdd;
-    private Update<AgentInformation> mockUpdate;
-    private Replace<AgentInformation> mockReplace;
-    private Remove<AgentInformation> mockRemove;
-    
-    @SuppressWarnings("unchecked")
-    @Before
-    public void setup() {
-        storage = mock(BackingStorage.class);
-        mockQuery = mock(Query.class);
-        aggQuery = mock(AggregateQuery.class);
-        // setup for QUERY/QUERY-COUNT/QUERY-DISTINCT
-        when(storage.createQuery(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockQuery);
-        when(storage.createAggregateQuery(eq(AggregateFunction.COUNT), (eq(AgentInfoDAO.CATEGORY)))).thenReturn(aggQuery);
-        when(storage.createAggregateQuery(eq(AggregateFunction.DISTINCT), (eq(AgentInfoDAO.CATEGORY)))).thenReturn(aggQuery);
-        // setup for ADD
-        mockAdd = mock(Add.class);
-        when(storage.createAdd(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockAdd);
-        // setup for UPDATE
-        mockUpdate = mock(Update.class);
-        when(storage.createUpdate(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockUpdate);
-        // setup for REMOVE
-        mockRemove = mock(Remove.class);
-        when(storage.createRemove(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockRemove);
-        // setup for REPLACE
-        mockReplace = mock(Replace.class);
-        when(storage.createReplace(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockReplace);
-    }
-    
-    @Test
-    public void canParseQueryWithLimit() throws DescriptorParsingException {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT 1";
-        doSemanticsBasicParseTest(descString);
-        
-    }
-    
-    @Test
-    public void catParseQueryCountWithLimit() throws DescriptorParsingException {
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.COUNT);
-        String descString = "QUERY-COUNT " + AgentInfoDAO.CATEGORY.getName() + " LIMIT 1";
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    @Test
-    public void canParseQueryCountWithCorrectKeyParam() throws DescriptorParsingException {
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.COUNT);
-        String descString = "QUERY-COUNT(" + Key.AGENT_ID.getName() + ") "
-                              + AgentInfoDAO.CATEGORY.getName();
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Test
-    public void canParseQueryDistinctWithCorrectKeyParam() throws DescriptorParsingException {
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.DISTINCT);
-        when(aggQuery.getAggregateKey()).thenReturn((Key)Key.AGENT_ID);
-        String descString = "QUERY-DISTINCT(" + Key.AGENT_ID.getName() + ") "
-                              + AgentInfoDAO.CATEGORY.getName();
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    @Test
-    public void canParseQueryWithSort() throws DescriptorParsingException {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT 'foo' DSC";
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    @Test
-    public void catParseQueryCountWithSort() throws DescriptorParsingException {
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.COUNT);
-        String descString = "QUERY-COUNT " + AgentInfoDAO.CATEGORY.getName() + " SORT 'foo' DSC";
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    /*
-     * Tests whether parse succeeds if some properties are missing from the
-     * UPDATE descriptor. Update is the operation to be used in this case.
-     */
-    @Test
-    public void canParseUpdateWithSomePropertiesMissing() throws DescriptorParsingException {
-        String descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() +
-                    " SET '" + Key.AGENT_ID.getName() + "' = 'b' , " + 
-                         "'"+ AgentInfoDAO.ALIVE_KEY.getName() + "' = ?b" +
-                    " WHERE '" + Key.AGENT_ID.getName() + "' = ?s";
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    /*
-     * Tests whether parse succeeds if ALL properties are given in the
-     * ADD descriptor.
-     */
-    @Test
-    public void canParseAddWithAllPropertiesGiven() throws DescriptorParsingException {
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " " + COMPLETE_SET_LIST_AGENT_INFO;
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    /*
-     * Tests whether parse succeeds if ALL properties are given in the
-     * REPLACE descriptor.
-     */
-    @Test
-    public void canParseReplaceWithAllPropertiesGiven() throws DescriptorParsingException {
-        String descString = "REPLACE " + AgentInfoDAO.CATEGORY.getName() +
-                " " + COMPLETE_SET_LIST_AGENT_INFO +
-                " WHERE '" + AgentInfoDAO.CONFIG_LISTEN_ADDRESS.getName()+ "' = ?s";
-        doSemanticsBasicParseTest(descString);
-    }
-    
-    private void doSemanticsBasicParseTest(String strDesc) throws DescriptorParsingException {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        ParsedStatement<AgentInformation> p = parser.parse();
-        assertNotNull(p);
-    }
-    
-    /*
-     * Tests whether we appropriately reject a provided key parameter in a
-     * query-count aggregate for which the key is unknown in the given category.
-     */
-    @Test
-    public void rejectQueryCountWithUnknownKeyAsParam() throws DescriptorParsingException {
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.COUNT);
-        doRejectQueryAggregateTestWithParam(AggregateFunction.COUNT);
-    }
-    
-    /*
-     * Tests whether we appropriately reject a provided key parameter in a
-     * query-distinct aggregate for which the key is unknown in the given category.
-     */
-    @Test
-    public void rejectQueryDistinctWithUnknownKeyAsParam() throws DescriptorParsingException {
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.DISTINCT);
-        doRejectQueryAggregateTestWithParam(AggregateFunction.DISTINCT);
-    }
-    
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private void doRejectQueryAggregateTestWithParam(AggregateFunction function) {
-        String unknownKeyName = "unknown_key";
-        Key unknownKey = new Key(unknownKeyName);
-        when(aggQuery.getAggregateKey()).thenReturn(unknownKey);
-        String format = "QUERY-%s(%s) %s";
-        String descString = String.format(format, function.name(), unknownKeyName, AgentInfoDAO.CATEGORY.getName());
-        assertNull("Precondition failed. unknown_key in AgentInfo category?",
-                AgentInfoDAO.CATEGORY.getKey(unknownKeyName));
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail(String.format("QUERY-%s with an unknown key as param should not parse", function.name()));
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Unknown aggregate key '" + unknownKeyName + "'"));
-        }
-    }
-    
-    /*
-     * Distinct queries aggregate by selecting all distinct values for a
-     * given key. Not providing a key for which to find distinct values for 
-     * doesn't make sense.
-     */
-    @Test
-    public void rejectQueryDistinctWithoutKeyParam() throws DescriptorParsingException {
-        String descString = "QUERY-DISTINCT " + AgentInfoDAO.CATEGORY.getName();
-        
-        when(aggQuery.getAggregateKey()).thenReturn(null);
-        when(aggQuery.getAggregateFunction()).thenReturn(AggregateFunction.DISTINCT);
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("QUERY-DISTINCT without a key for which to produce distinct values for should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Aggregate key for DISTINCT must not be null"));
-        }
-    }
-    
-    @Test
-    public void rejectAddWithWhere() throws DescriptorParsingException {
-        String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " " + COMPLETE_SET_LIST_AGENT_INFO + " WHERE 'a' = 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("ADD operation does not support WHERE clauses!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("WHERE clause not allowed for ADD"));
-        }
-    }
-    
-    @Test
-    public void rejectReplaceWithoutWhere() throws DescriptorParsingException {
-        String descString = "REPLACE " + AgentInfoDAO.CATEGORY.getName() + " " + COMPLETE_SET_LIST_AGENT_INFO;
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("REPLACE operation requires WHERE clause, and should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("WHERE clause required for REPLACE"));
-        }
-    }
-    
-    @Test
-    public void rejectUpdateWithoutWhere() throws DescriptorParsingException {
-        String descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() +
-                " SET '" + Key.AGENT_ID.getName() + "' = 'b' , 'c' = 'd'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("UPDATE operation requires WHERE clause, and should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("WHERE clause required for UPDATE"));
-        }
-    }
-    
-    @Test
-    public void rejectRemoveWithSetList() throws DescriptorParsingException {
-        String descString = "REMOVE " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = 'b'" +
-                                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("REMOVE does not allow SET list, and should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue("message was: " + e.getMessage(), e.getMessage().contains("SET not allowed for REMOVE"));
-        }
-    }
-    
-    @Test
-    public void rejectQueryWithSetList() throws DescriptorParsingException {
-        String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = 'b'" +
-                                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("QUERY does not allow SET list, and should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("SET not allowed for QUERY"));
-        }
-    }
-    
-    
-    private void doRejectWriteSortLimitTest(String descString, String failmsg) {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail(failmsg);
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertEquals("LIMIT/SORT only allowed for QUERY/QUERY-COUNT", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void rejectWritesWithSortLimit() throws DescriptorParsingException {
-        // Update rejects
-        String descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() +
-                " SET '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " SORT 'a' DSC"; // this is intentionally wrong for this test
-        String failmsg = "SORT in UPDATE is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() +
-                " SET '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " LIMIT 1"; // this is intentionally wrong for this test
-        failmsg = "LIMIT in UPDATE is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        
-        // Remove rejects
-        descString = "REMOVE " + AgentInfoDAO.CATEGORY.getName() +
-                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " LIMIT 1"; // this is intentionally wrong for this test
-        failmsg = "LIMIT in REMOVE is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        descString = "REMOVE " + AgentInfoDAO.CATEGORY.getName() +
-                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " SORT 'a' ASC";
-        failmsg = "SORT in REMOVE is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        
-        // Replace rejects
-        descString = "REPLACE " + AgentInfoDAO.CATEGORY.getName() + " " +
-                COMPLETE_SET_LIST_AGENT_INFO +
-                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " LIMIT 1";
-        failmsg = "LIMIT in REPLACE is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        descString = "REPLACE " + AgentInfoDAO.CATEGORY.getName() + " " +
-                COMPLETE_SET_LIST_AGENT_INFO +
-                " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'" +
-                " SORT 'a' ASC";
-        failmsg = "SORT in REPLACE is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        
-        // Add rejects
-        descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " " + COMPLETE_SET_LIST_AGENT_INFO + " LIMIT 1";
-        failmsg = "LIMIT in ADD is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-        descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " " + COMPLETE_SET_LIST_AGENT_INFO + " SORT 'a' ASC";
-        failmsg = "SORT in ADD is not allowed, and should not parse!";
-        doRejectWriteSortLimitTest(descString, failmsg);
-    }
-    
-    @Test
-    public void rejectUpdateWithoutSet() throws DescriptorParsingException {
-        String descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() + " WHERE '" + Key.AGENT_ID.getName() + "' = 'b'";
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("UPDATE requires SET list, and should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertEquals("SET list required for UPDATE", e.getMessage());
-        }
-    }
-    
-    /*
-     * Tests whether parser fails if some properties are missing from the
-     * ADD descriptor, but the category specified as keys.
-     */
-    @Test
-    public void rejectAddWithSomePropertiesMissing() throws DescriptorParsingException {
-        String strDesc = "ADD " + AgentInfoDAO.CATEGORY.getName() + " " + INCOMPLETE_SET_LIST_AGENT_INFO;
-        doRejectIncompleteKeysTest(strDesc);
-    }
-    
-    /*
-     * Tests whether parser fails if some properties are missing from the
-     * REPLACE descriptor, but the category specified as keys.
-     */
-    @Test
-    public void rejectReplaceWithSomePropertiesMissing() throws DescriptorParsingException {
-        // The following descriptor should be valid except for the one missing key.
-        String strDesc = "REPLACE " + AgentInfoDAO.CATEGORY.getName() + " "
-                        + INCOMPLETE_SET_LIST_AGENT_INFO + " WHERE 'foo' = ?s";
-        doRejectIncompleteKeysTest(strDesc);
-    }
-
-    private void doRejectIncompleteKeysTest(String strDesc) {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("stop timestamp key missing. Should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Keys don't match keys in category."));
-        }
-    }
-    
-    /*
-     * Tests whether parser fails if LHS of any SET pair of ADD/REPLACE is a
-     * free variable. We disallow this, since key completeness checks don't make
-     * much sense (prior patching) without this.
-     */
-    @Test
-    public void rejectAddReplaceWithFreeVarOnLHS() throws DescriptorParsingException {
-        // second pair has ?s as LHS 
-        String strDesc = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET " + 
-                "'" + Key.AGENT_ID.getName() + "' = ?s , ?s = ?b";
-        doRejectWithFreeVarOnLHS(strDesc);
-        
-        // ?b is the offending part
-        strDesc = "REPLACE " + AgentInfoDAO.CATEGORY.getName() + " SET " + 
-                "?b = ?s WHERE 'foo' = ?s";
-        doRejectWithFreeVarOnLHS(strDesc);
-    }
-
-    private void doRejectWithFreeVarOnLHS(String strDesc) {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("SET with free variable on LHS should not parse!");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertEquals("LHS of set list pair must not be a free variable.", e.getMessage());
-        }
-    }
-    
-    /*
-     * Tests whether a key set via UPDATE exists in the category. 
-     */
-    @Test
-    public void rejectUpdateWithUnknownKeyInSet() {
-        String descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() + " SET 'iDoNotExist' = ?s WHERE 'foo' = 'b'";
-        String detail = "'[iDoNotExist]'";
-        doRejectUpdateWithUnknownKeyTest(descString, detail);
-        descString = "UPDATE " + AgentInfoDAO.CATEGORY.getName() + " SET 'iDoNotExist' = ?s , 'notHere' = ?b WHERE 'foo' = 'b'";
-        detail = "'[iDoNotExist, notHere]'";
-        doRejectUpdateWithUnknownKeyTest(descString, detail);
-    }
-
-    private void doRejectUpdateWithUnknownKeyTest(String descString,
-            String detailMsg) {
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
-        parser = new SemanticsEnabledDescriptorParser<>(storage, desc);
-        try {
-            parser.parse();
-            fail("SET for unknown key in category should not parse");
-        } catch (DescriptorParsingException e) {
-            // pass
-            assertEquals("Unknown key(s) in SET: " + detailMsg, e.getMessage());
-        }
-    }
-    
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SetListValueTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class SetListValueTest {
-
-    @Test
-    public void testEqualsHashCodeEmpty() {
-        SetListValue value = new SetListValue();
-        assertTrue(value.equals(value));
-        SetListValue value2 = new SetListValue();
-        assertTrue(value.equals(value2));
-        assertEquals(value.hashCode(), value2.hashCode());
-    }
-    
-    @Test
-    public void testEqualsHashCodeNonEmpty() {
-        TerminalNode keyNode = new TerminalNode(null);
-        keyNode.setValue("foo");
-        TerminalNode valNode = new TerminalNode(null);
-        valNode.setValue("bar-val");
-        SetListValue value = new SetListValue();
-        value.setKey(keyNode);
-        value.setValue(valNode);
-        assertTrue(value.equals(value));
-        SetListValue value2 = new SetListValue();
-        TerminalNode keyNode2 = new TerminalNode(null);
-        keyNode2.setValue("foo");
-        TerminalNode valNode2 = new TerminalNode(null);
-        valNode2.setValue("bar-val");
-        value2.setKey(keyNode2);
-        value2.setValue(valNode2);
-        assertEquals(valNode, valNode2);
-        assertEquals(keyNode, keyNode2);
-        assertTrue(value.equals(value2));
-        assertEquals(value.hashCode(), value2.hashCode());
-        assertFalse(value.equals("something-else"));
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SortMemberTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
-
-public class SortMemberTest {
-    
-    private SortMember member;
-    
-    @Before
-    public void setup() {
-        member = new SortMember();
-        member.setDirection(SortDirection.ASCENDING);
-        UnfinishedSortKey unfinished = new UnfinishedSortKey();
-        unfinished.setParameterIndex(0);
-        member.setSortKey(unfinished);
-    }
-
-    @Test
-    public void testPatchWithString() {
-        PreparedParameter p = new PreparedParameter();
-        p.setType(String.class);
-        p.setValue("foo");
-        PatchedSortMemberExpression expn = null;
-        try {
-            // test patching
-            expn = member.patch(new PreparedParameter[] { p });
-            // pass
-        } catch (IllegalPatchException e) {
-            fail(e.getMessage());
-        }
-        assertNotNull(expn);
-        assertEquals(new Key<>("foo"), expn.getSortMember().getSortKey());
-    }
-    
-    @Test
-    public void rejectPatchWithStringList() {
-        PreparedParameter p = new PreparedParameter();
-        p.setType(String[].class);
-        p.setValue(new String[] { "foo" });
-        try {
-            member.patch(new PreparedParameter[] { p });
-            fail("Patching with string list should not be possible!");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Illegal parameter type"));
-        }
-    }
-    
-    @Test
-    public void rejectPatchWithNumber() {
-        PreparedParameter p = new PreparedParameter();
-        p.setType(int.class);
-        p.setValue(1);
-        try {
-            member.patch(new PreparedParameter[] { p });
-            fail("Patching with integer should not be possible!");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("Illegal parameter type"));
-        }
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorTester.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/*
- * NOTE class copied from storage-test-utils for internal testing of Statement
- * Adapters
- */
-public final class StatementDescriptorTester<T extends Pojo> {
-
-    public void testParseBasic(StatementDescriptor<T> desc)
-            throws DescriptorParsingException {
-        TestParser<T> testParser = new TestParser<>(desc, ParserType.BASIC);
-        testParser.parse();
-    }
-    
-    public void testParseSemantic(StatementDescriptor<T> desc) throws DescriptorParsingException {
-        TestParser<T> testParser = new TestParser<>(desc, ParserType.SEMANTIC);
-        testParser.parse();
-    }
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/TerminalNodeTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.model.AgentInformation;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.LiteralExpression;
-
-public class TerminalNodeTest {
-
-    @Test
-    public void canPatchWithCorrectType() {
-        TerminalNode node = new TerminalNode(null);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setParameterIndex(0);
-        unfinished.setType(String.class);
-        
-        node.setValue(unfinished);
-        
-        PreparedParameter p = new PreparedParameter();
-        p.setType(String.class);
-        p.setValue("foo-bar");
-        
-        PatchedWhereExpression expn = null;
-        try {
-            expn = node.patch(new PreparedParameter[] { p });
-            // pass
-        } catch (IllegalPatchException e) {
-            fail(e.getMessage());
-        }
-        assertNotNull(expn);
-        LiteralExpression<?> literal = (LiteralExpression<?>)expn.getExpression();
-        assertEquals("foo-bar", literal.getValue());
-    }
-    
-    @Test
-    public void canPatchWithPojoType() {
-        TerminalNode node = new TerminalNode(null);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setParameterIndex(0);
-        unfinished.setType(Pojo.class);
-        
-        node.setValue(unfinished);
-        
-        PreparedParameter p = new PreparedParameter();
-        p.setType(AgentInformation.class);
-        AgentInformation info = new AgentInformation("foo-bar");
-        p.setValue(info);
-        
-        PatchedWhereExpression expn = null;
-        try {
-            expn = node.patch(new PreparedParameter[] { p });
-            // pass
-        } catch (IllegalPatchException e) {
-            fail(e.getMessage());
-        }
-        assertNotNull(expn);
-        LiteralExpression<?> literal = (LiteralExpression<?>)expn.getExpression();
-        assertEquals(info, literal.getValue());
-    }
-    
-    @Test
-    public void rejectPatchingWithIncorrectListType() {
-        TerminalNode node = new TerminalNode(null);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setParameterIndex(0);
-        unfinished.setType(String.class);
-        
-        node.setValue(unfinished);
-        
-        PreparedParameter p = new PreparedParameter();
-        p.setType(String[].class);
-        p.setValue(new String[] { "foo-bar" });
-        
-        try {
-            node.patch(new PreparedParameter[] { p });
-            fail("Should not be able to patch string with string list.");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("invalid type when attempting to patch."));
-        }
-    }
-    
-    @Test
-    public void rejectPatchingWithIncorrectPojoListType() {
-        TerminalNode node = new TerminalNode(null);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setParameterIndex(0);
-        unfinished.setType(Pojo.class);
-        
-        node.setValue(unfinished);
-        
-        PreparedParameter p = new PreparedParameter();
-        p.setType(AgentInformation.class);
-        AgentInformation info = new AgentInformation("testing");
-        p.setValue(new AgentInformation[] { info });
-        
-        try {
-            node.patch(new PreparedParameter[] { p });
-            fail("Should not be able to patch string with string list.");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("invalid type when attempting to patch."));
-        }
-    }
-    
-    @Test
-    public void rejectPatchingWithIncorrectType() {
-        TerminalNode node = new TerminalNode(null);
-        UnfinishedValueNode unfinished = new UnfinishedValueNode();
-        unfinished.setLHS(false);
-        unfinished.setParameterIndex(0);
-        unfinished.setType(int.class);
-        
-        node.setValue(unfinished);
-        
-        PreparedParameter p = new PreparedParameter();
-        p.setType(String[].class);
-        p.setValue(new String[] { "foo-bar" });
-        
-        try {
-            node.patch(new PreparedParameter[] { p });
-            fail("Should not be able to patch integer with string list.");
-        } catch (IllegalPatchException e) {
-            // pass
-            assertTrue(e.getMessage().contains("invalid type when attempting to patch."));
-        }
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/TestParser.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/*
- * NOTE class copied from storage-test-utils for internal testing
- */
-public final class TestParser<T extends Pojo> implements StatementDescriptorParser<T> {
-
-    private final StatementDescriptor<T> desc;
-    private final DescriptorParserImplFactory factory;
-    private final ParserType type;
-    
-    public TestParser(StatementDescriptor<T> desc, ParserType type) {
-        this.desc = desc;
-        this.factory = new DescriptorParserImplFactory();
-        this.type = type;
-    }
-    
-    @Override
-    public ParsedStatement<T> parse() throws DescriptorParsingException {
-        StatementDescriptorParser<T> actualParser = factory.getParser(type, desc);
-        actualParser.parse();
-        return null; // Always return null. Testing utility only.
-    }
-
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressions.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import com.redhat.thermostat.storage.internal.statement.BinaryExpressionNode;
-import com.redhat.thermostat.storage.internal.statement.Node;
-import com.redhat.thermostat.storage.internal.statement.NotBooleanExpressionNode;
-import com.redhat.thermostat.storage.internal.statement.TerminalNode;
-import com.redhat.thermostat.storage.internal.statement.WhereExpression;
-
-/**
- * Helper class for comparing where expression trees.
- *
- * @see BasicDescriptorParserTest
- */
-public class WhereExpressions {
-
-    /**
-     * Compares two where expression parse trees.
-     * 
-     * @param a
-     * @param b
-     * @return true, if all nodes/values were equal. false otherwise.
-     */
-    public static boolean equals(WhereExpression a, WhereExpression b) {
-        Node aRoot = a.getRoot();
-        Node bRoot = b.getRoot();
-        return recEquals(aRoot, bRoot);
-    }
-    
-    private static boolean recEquals(Node a, Node b) {
-        boolean retval = Objects.equals(a, b);
-        if (!retval) {
-            return false;
-        }
-        Node[] nextNodesA = getNextNodes(a);
-        Node[] nextNodesB = getNextNodes(b);
-        if (nextNodesA != null && nextNodesB != null) {
-            retval = retval && (nextNodesA.length == nextNodesB.length);
-            if (!retval) {
-                return false;
-            }
-            // verify nodes at this level are equal
-            for (int i = 0; i < nextNodesA.length; i++) {
-                retval = retval && Objects.equals(nextNodesA[i], nextNodesB[i]);
-                if (!retval) {
-                    return false;
-                }
-            }
-            // recursively check child nodes
-            for (int i = 0; i < nextNodesA.length; i++) {
-                retval = retval && recEquals(nextNodesA[i], nextNodesB[i]);
-                if (!retval) {
-                    return false;
-                }
-            }
-            return retval;
-        }
-        if (nextNodesA != null || nextNodesB != null) {
-            return false;
-        }
-        // all pass
-        return true;
-    }
-
-    private static Node[] getNextNodes(Node node) {
-        if (node instanceof TerminalNode) {
-            return null;
-        } else if (node instanceof BinaryExpressionNode) {
-            List<Node> nodes = new ArrayList<>(2);
-            BinaryExpressionNode binNode = (BinaryExpressionNode)node;
-            if (binNode.getLeftChild() != null) {
-                nodes.add(binNode.getLeftChild());
-            }
-            if (binNode.getRightChild() != null) {
-                nodes.add(binNode.getRightChild());
-            }
-            if (nodes.size() == 0) {
-                return null;
-            }
-            return nodes.toArray(new Node[0]);
-        } else if (node instanceof NotBooleanExpressionNode || node instanceof Node) {
-            Node next = (Node)node.getValue();
-            if (next == null) {
-                return null;
-            }
-            return new Node[] { next };
-        } else {
-            return null;
-        }
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressionsTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,286 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.internal.statement.BinaryExpressionNode;
-import com.redhat.thermostat.storage.internal.statement.NotBooleanExpressionNode;
-import com.redhat.thermostat.storage.internal.statement.TerminalNode;
-import com.redhat.thermostat.storage.internal.statement.WhereExpression;
-import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
-import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
-
-public class WhereExpressionsTest {
-
-    @Test
-    public void testEqualsSelf() {
-        WhereExpression expn1 = new WhereExpression();
-        assertTrue(WhereExpressions.equals(expn1, expn1));
-    }
-    
-    @Test
-    public void testEqualsEmpty() {
-        WhereExpression expn1 = new WhereExpression();
-        WhereExpression expn2 = new WhereExpression();
-        assertTrue(WhereExpressions.equals(expn1, expn2));
-    }
-    
-    @Test
-    public void testEqualsSimpleTerminal() {
-        WhereExpression expn1 = new WhereExpression();
-        WhereExpression expn2 = new WhereExpression();
-        TerminalNode node = new TerminalNode(expn1.getRoot());
-        node.setValue("testing");
-        TerminalNode node2 = new TerminalNode(expn2.getRoot());
-        node2.setValue("testing");
-        expn1.getRoot().setValue(node);
-        expn2.getRoot().setValue(node2);
-        assertTrue(WhereExpressions.equals(expn1, expn2));
-    }
-    
-    @Test
-    public void testEqualsSimpleTerminalWithDifferentValues() {
-        WhereExpression expn1 = new WhereExpression();
-        WhereExpression expn2 = new WhereExpression();
-        TerminalNode node = new TerminalNode(expn1.getRoot());
-        node.setValue("test");
-        TerminalNode node2 = new TerminalNode(expn2.getRoot());
-        node2.setValue("other");
-        expn1.getRoot().setValue(node);
-        expn2.getRoot().setValue(node2);
-        assertFalse(WhereExpressions.equals(expn1, expn2));
-    }
-    
-    @Test
-    public void testEqualsComplexish() {
-        WhereExpression expn1 = new WhereExpression();
-        BinaryExpressionNode binNode1 = new BinaryExpressionNode(expn1.getRoot());
-        expn1.getRoot().setValue(binNode1);
-        binNode1.setOperator(BinaryLogicalOperator.OR);
-        NotBooleanExpressionNode notNode1 = new NotBooleanExpressionNode(binNode1);
-        TerminalNode termNode1 = new TerminalNode(notNode1);
-        termNode1.setValue("testing");
-        notNode1.setValue(termNode1);
-        binNode1.setLeftChild(notNode1);
-        BinaryExpressionNode and1 = new BinaryExpressionNode(binNode1);
-        binNode1.setRightChild(and1);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode left1 = new BinaryExpressionNode(and1);
-        left1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode termNode1Equal = new TerminalNode(left1);
-        termNode1Equal.setValue("a");
-        TerminalNode termNode1EqualOther = new TerminalNode(left1);
-        termNode1EqualOther.setValue("b");
-        left1.setLeftChild(termNode1Equal);
-        left1.setRightChild(termNode1EqualOther);
-        and1.setLeftChild(left1);
-        BinaryExpressionNode right1 = new BinaryExpressionNode(and1);
-        right1.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-        TerminalNode termNode1LessEqual = new TerminalNode(right1);
-        termNode1LessEqual.setValue("x");
-        TerminalNode termNode1LessEqualOther = new TerminalNode(right1);
-        termNode1LessEqualOther.setValue("y");
-        right1.setLeftChild(termNode1LessEqual);
-        right1.setRightChild(termNode1LessEqualOther);
-        and1.setRightChild(right1);
-        
-        // now build the second and equal where expn
-        WhereExpression expn2 = new WhereExpression();
-        BinaryExpressionNode binNode2 = new BinaryExpressionNode(expn2.getRoot());
-        expn2.getRoot().setValue(binNode2);
-        binNode2.setOperator(BinaryLogicalOperator.OR);
-        NotBooleanExpressionNode notNode2 = new NotBooleanExpressionNode(binNode2);
-        TerminalNode termNode2 = new TerminalNode(notNode2);
-        termNode2.setValue("testing");
-        notNode2.setValue(termNode2);
-        binNode2.setLeftChild(notNode2);
-        BinaryExpressionNode and2 = new BinaryExpressionNode(binNode2);
-        binNode2.setRightChild(and2);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode left2 = new BinaryExpressionNode(and2);
-        left2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode termNode2Equal = new TerminalNode(left2);
-        termNode2Equal.setValue("a");
-        TerminalNode termNode2EqualOther = new TerminalNode(left2);
-        termNode2EqualOther.setValue("b");
-        left2.setLeftChild(termNode2Equal);
-        left2.setRightChild(termNode2EqualOther);
-        and2.setLeftChild(left2);
-        BinaryExpressionNode right2 = new BinaryExpressionNode(and2);
-        right2.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-        TerminalNode termNode2LessEqual = new TerminalNode(right2);
-        termNode2LessEqual.setValue("x");
-        TerminalNode termNode2LessEqualOther = new TerminalNode(right2);
-        termNode2LessEqualOther.setValue("y");
-        right2.setLeftChild(termNode2LessEqual);
-        right2.setRightChild(termNode2LessEqualOther);
-        and2.setRightChild(right2);
-        assertTrue(WhereExpressions.equals(expn1, expn2));
-    }
-    
-    @Test
-    public void testNotEqualsComplexish() {
-        WhereExpression expn1 = new WhereExpression();
-        BinaryExpressionNode binNode1 = new BinaryExpressionNode(expn1.getRoot());
-        expn1.getRoot().setValue(binNode1);
-        binNode1.setOperator(BinaryLogicalOperator.OR);
-        NotBooleanExpressionNode notNode1 = new NotBooleanExpressionNode(binNode1);
-        TerminalNode termNode1 = new TerminalNode(notNode1);
-        termNode1.setValue("testing");
-        notNode1.setValue(termNode1);
-        binNode1.setLeftChild(notNode1);
-        BinaryExpressionNode and1 = new BinaryExpressionNode(binNode1);
-        binNode1.setRightChild(and1);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode left1 = new BinaryExpressionNode(and1);
-        left1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode termNode1Equal = new TerminalNode(left1);
-        termNode1Equal.setValue("d"); // should be "a" to make it equal
-        TerminalNode termNode1EqualOther = new TerminalNode(left1);
-        termNode1EqualOther.setValue("b");
-        left1.setLeftChild(termNode1Equal);
-        left1.setRightChild(termNode1EqualOther);
-        and1.setLeftChild(left1);
-        BinaryExpressionNode right1 = new BinaryExpressionNode(and1);
-        right1.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-        TerminalNode termNode1LessEqual = new TerminalNode(right1);
-        termNode1LessEqual.setValue("x");
-        TerminalNode termNode1LessEqualOther = new TerminalNode(right1);
-        termNode1LessEqualOther.setValue("y");
-        right1.setLeftChild(termNode1LessEqual);
-        right1.setRightChild(termNode1LessEqualOther);
-        and1.setRightChild(right1);
-        
-        // now build the second and equal where expn
-        WhereExpression expn2 = new WhereExpression();
-        BinaryExpressionNode binNode2 = new BinaryExpressionNode(expn2.getRoot());
-        expn2.getRoot().setValue(binNode2);
-        binNode2.setOperator(BinaryLogicalOperator.OR);
-        NotBooleanExpressionNode notNode2 = new NotBooleanExpressionNode(binNode2);
-        TerminalNode termNode2 = new TerminalNode(notNode2);
-        termNode2.setValue("testing");
-        notNode2.setValue(termNode2);
-        binNode2.setLeftChild(notNode2);
-        BinaryExpressionNode and2 = new BinaryExpressionNode(binNode2);
-        binNode2.setRightChild(and2);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode left2 = new BinaryExpressionNode(and2);
-        left2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode termNode2Equal = new TerminalNode(left2);
-        termNode2Equal.setValue("a");
-        TerminalNode termNode2EqualOther = new TerminalNode(left2);
-        termNode2EqualOther.setValue("b");
-        left2.setLeftChild(termNode2Equal);
-        left2.setRightChild(termNode2EqualOther);
-        and2.setLeftChild(left2);
-        BinaryExpressionNode right2 = new BinaryExpressionNode(and2);
-        right2.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-        TerminalNode termNode2LessEqual = new TerminalNode(right2);
-        termNode2LessEqual.setValue("x");
-        TerminalNode termNode2LessEqualOther = new TerminalNode(right2);
-        termNode2LessEqualOther.setValue("y");
-        right2.setLeftChild(termNode2LessEqual);
-        right2.setRightChild(termNode2LessEqualOther);
-        and2.setRightChild(right2);
-        assertFalse(WhereExpressions.equals(expn1, expn2));
-    }
-    
-    @Test
-    public void testNotEqualsNotSameTreeAtAll() {
-        WhereExpression expn1 = new WhereExpression();
-        BinaryExpressionNode binNode1 = new BinaryExpressionNode(expn1.getRoot());
-        expn1.getRoot().setValue(binNode1);
-        binNode1.setOperator(BinaryLogicalOperator.OR);
-        NotBooleanExpressionNode notNode1 = new NotBooleanExpressionNode(binNode1);
-        TerminalNode termNode1 = new TerminalNode(notNode1);
-        termNode1.setValue("testing");
-        notNode1.setValue(termNode1);
-        binNode1.setLeftChild(notNode1);
-        BinaryExpressionNode and1 = new BinaryExpressionNode(binNode1);
-        binNode1.setRightChild(and1);
-        and1.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode left1 = new BinaryExpressionNode(and1);
-        left1.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode termNode1Equal = new TerminalNode(left1);
-        termNode1Equal.setValue("d"); // should be "a" to make it equal
-        TerminalNode termNode1EqualOther = new TerminalNode(left1);
-        termNode1EqualOther.setValue("b");
-        left1.setLeftChild(termNode1Equal);
-        left1.setRightChild(termNode1EqualOther);
-        and1.setLeftChild(left1);
-        BinaryExpressionNode right1 = new BinaryExpressionNode(and1);
-        right1.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-        TerminalNode termNode1LessEqual = new TerminalNode(right1);
-        termNode1LessEqual.setValue("x");
-        TerminalNode termNode1LessEqualOther = new TerminalNode(right1);
-        termNode1LessEqualOther.setValue("y");
-        right1.setLeftChild(termNode1LessEqual);
-        right1.setRightChild(termNode1LessEqualOther);
-        and1.setRightChild(right1);
-        
-        // now build the second fairly different tree
-        WhereExpression expn2 = new WhereExpression();
-        NotBooleanExpressionNode notNode2 = new NotBooleanExpressionNode(expn2.getRoot());
-        BinaryExpressionNode and2 = new BinaryExpressionNode(notNode2);
-        notNode2.setValue(and2);
-        and2.setOperator(BinaryLogicalOperator.AND);
-        BinaryExpressionNode left2 = new BinaryExpressionNode(and2);
-        left2.setOperator(BinaryComparisonOperator.EQUALS);
-        TerminalNode termNode2Equal = new TerminalNode(left2);
-        termNode2Equal.setValue("a");
-        TerminalNode termNode2EqualOther = new TerminalNode(left2);
-        termNode2EqualOther.setValue("b");
-        left2.setLeftChild(termNode2Equal);
-        left2.setRightChild(termNode2EqualOther);
-        and2.setLeftChild(left2);
-        BinaryExpressionNode right2 = new BinaryExpressionNode(and2);
-        right2.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
-        TerminalNode termNode2LessEqual = new TerminalNode(right2);
-        termNode2LessEqual.setValue("x");
-        TerminalNode termNode2LessEqualOther = new TerminalNode(right2);
-        termNode2LessEqualOther.setValue("y");
-        right2.setLeftChild(termNode2LessEqual);
-        right2.setRightChild(termNode2LessEqualOther);
-        and2.setRightChild(right2);
-        assertFalse(WhereExpressions.equals(expn1, expn2));
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/query/BinaryExpressionTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Before;
-import org.junit.Test;
-
-
-public class BinaryExpressionTest {
-    
-    private Expression left;
-    private Expression right;
-    private BinaryOperator op;
-    private BinaryExpression<Expression, Expression, BinaryOperator> expr;
-
-    @Before
-    public void setup() {
-        left = mock(Expression.class);
-        right = mock(Expression.class);
-        op = mock(BinaryOperator.class);
-        expr = new BinaryExpression<Expression, Expression, BinaryOperator>(
-                left, op, right) {
-        };
-    }
-    
-    @Test
-    public void testGetLeftOperand() {
-        assertEquals(left, expr.getLeftOperand());
-    }
-    
-    @Test
-    public void testGetRightOperand() {
-        assertEquals(right, expr.getRightOperand());
-    }
-    
-    @Test
-    public void testGetOperator() {
-        assertEquals(op, expr.getOperator());
-    }
-    
-    @Test
-    public void testEquals() {
-        BinaryExpression<Expression, Expression, BinaryOperator> otherExpr = new BinaryExpression<Expression, Expression, BinaryOperator>(
-                left, op, right) {
-        };
-        assertEquals(expr, otherExpr);
-    }
-    
-    @Test
-    public void testNotEquals() {
-        Expression otherLeft = mock(Expression.class);
-        BinaryExpression<Expression, Expression, BinaryOperator> otherExpr = new BinaryExpression<Expression, Expression, BinaryOperator>(
-                otherLeft, op, right) {
-        };
-        
-        assertFalse(expr.equals(otherExpr));
-    }
-    
-    @Test
-    public void testNotEqualsWrongClass() {
-        assertFalse(expr.equals(new Object()));
-    }
-    
-    @Test
-    public void testNotEqualsNull() {
-        assertFalse(expr.equals(null));
-    }
-    
-    @Test
-    public void testHashCode() {
-        int hashCode = left.hashCode() + right.hashCode() + op.hashCode();
-        assertEquals(hashCode, expr.hashCode());
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/query/ExpressionFactoryTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Key;
-
-public class ExpressionFactoryTest {
-    
-    private static final Key<String> key = new Key<>("hello");
-    private static final String VALUE = "world";
-    private static final Set<String> VALUES = new HashSet<>(Arrays.asList("world", "worlds"));
-    ExpressionFactory factory;
-
-    @Before
-    public void setUp() throws Exception {
-        factory = new ExpressionFactory();
-    }
-
-    @Test
-    public void testEqualTo() {
-        Expression expr = new BinaryComparisonExpression<>(
-                new LiteralExpression<>(key), BinaryComparisonOperator.EQUALS,
-                new LiteralExpression<>(VALUE));
-        assertEquals(expr, factory.equalTo(key, VALUE));
-    }
-
-    @Test
-    public void testNotEqualTo() {
-        Expression expr = new BinaryComparisonExpression<>(
-                new LiteralExpression<>(key), BinaryComparisonOperator.NOT_EQUAL_TO,
-                new LiteralExpression<>(VALUE));
-        assertEquals(expr, factory.notEqualTo(key, VALUE));
-    }
-
-    @Test
-    public void testGreaterThan() {
-        Expression expr = new BinaryComparisonExpression<>(
-                new LiteralExpression<>(key), BinaryComparisonOperator.GREATER_THAN,
-                new LiteralExpression<>(VALUE));
-        assertEquals(expr, factory.greaterThan(key, VALUE));
-    }
-
-    @Test
-    public void testLessThan() {
-        Expression expr = new BinaryComparisonExpression<>(
-                new LiteralExpression<>(key), BinaryComparisonOperator.LESS_THAN,
-                new LiteralExpression<>(VALUE));
-        assertEquals(expr, factory.lessThan(key, VALUE));
-    }
-
-    @Test
-    public void testGreaterThanOrEqualTo() {
-        Expression expr = new BinaryComparisonExpression<>(
-                new LiteralExpression<>(key), BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO,
-                new LiteralExpression<>(VALUE));
-        assertEquals(expr, factory.greaterThanOrEqualTo(key, VALUE));
-    }
-
-    @Test
-    public void testLessThanOrEqualTo() {
-        Expression expr = new BinaryComparisonExpression<>(
-                new LiteralExpression<>(key), BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO,
-                new LiteralExpression<>(VALUE));
-        assertEquals(expr, factory.lessThanOrEqualTo(key, VALUE));
-    }
-
-    @Test
-    public void testIn() {
-        Expression expr = new BinarySetMembershipExpression<>(
-                new LiteralExpression<>(key), BinarySetMembershipOperator.IN,
-                new LiteralSetExpression<>(VALUES, String.class));
-        assertEquals(expr, factory.in(key, VALUES, String.class));
-    }
-    
-    @Test
-    public void testNotIn() {
-        Expression expr = new BinarySetMembershipExpression<>(
-                new LiteralExpression<>(key), BinarySetMembershipOperator.NOT_IN,
-                new LiteralSetExpression<>(VALUES, String.class));
-        assertEquals(expr, factory.notIn(key, VALUES, String.class));
-    }
-    
-    @Test
-    public void testNot() {
-        ComparisonExpression operand = mock(ComparisonExpression.class);
-        Expression expr = new UnaryLogicalExpression<ComparisonExpression>(operand, UnaryLogicalOperator.NOT);
-        assertEquals(expr, factory.not(operand));
-    }
-
-    @Test
-    public void testAnd() {
-        Expression left = mock(Expression.class);
-        Expression right = mock(Expression.class);
-        Expression expr = new BinaryLogicalExpression<>(left, BinaryLogicalOperator.AND, right);
-        assertEquals(expr, factory.and(left, right));
-    }
-
-    @Test
-    public void testOr() {
-        Expression left = mock(Expression.class);
-        Expression right = mock(Expression.class);
-        Expression expr = new BinaryLogicalExpression<>(left, BinaryLogicalOperator.OR, right);
-        assertEquals(expr, factory.or(left, right));
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/query/LiteralExpressionTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class LiteralExpressionTest {
-
-    private Object value;
-    private LiteralExpression<Object> expr;
-
-    @Before
-    public void setup() {
-        value = new Object();
-        expr = new LiteralExpression<Object>(value);
-    }
-    
-    @Test
-    public void testGetValue() {
-        assertEquals(value, expr.getValue());
-    }
-    
-    @Test
-    public void testEquals() {
-        LiteralExpression<Object> otherExpr = new LiteralExpression<Object>(value);
-        assertEquals(expr, otherExpr);
-    }
-    
-    @Test
-    public void testNotEquals() {
-        Object otherValue = new Object();
-        LiteralExpression<Object> otherExpr = new LiteralExpression<Object>(otherValue);
-        
-        assertFalse(expr.equals(otherExpr));
-    }
-    
-    @Test
-    public void testNotEqualsWrongClass() {
-        assertFalse(expr.equals(new Object()));
-    }
-    
-    @Test
-    public void testNotEqualsNull() {
-        assertFalse(expr.equals(null));
-    }
-    
-    @Test
-    public void testHashCode() {
-        assertEquals(value.hashCode(), expr.hashCode());
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/query/LiteralSetExpressionTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class LiteralSetExpressionTest {
-
-    private static final Set<Object> VALUES = new HashSet<>(Arrays.asList(new Object(), new Object(), new Object()));
-    private LiteralSetExpression<Object> expr;
-
-    @Before
-    public void setup() {
-        expr = new LiteralSetExpression<Object>(VALUES, Object.class);
-    }
-    
-    @Test
-    public void testGetValues() {
-        assertEquals(VALUES, expr.getValues());
-    }
-    
-    @Test(expected=UnsupportedOperationException.class)
-    public void testGetValuesImmutable() {
-        Set<Object> values = expr.getValues();
-        values.add(new Object());
-    }
-    
-    @Test
-    public void testEquals() {
-        LiteralSetExpression<Object> otherExpr = new LiteralSetExpression<Object>(VALUES, Object.class);
-        assertEquals(expr, otherExpr);
-    }
-    
-    @Test
-    public void testDeepEquals() {
-        Set<Object> otherValues = new HashSet<>(VALUES);
-        LiteralSetExpression<Object> otherExpr = new LiteralSetExpression<Object>(otherValues, Object.class);
-        assertEquals(expr, otherExpr);
-    }
-    
-    @Test
-    public void testNotEquals() {
-        Set<Object> otherValue = new HashSet<>(Arrays.asList(new Object(), new Object(), new Object()));
-        LiteralSetExpression<Object> otherExpr = new LiteralSetExpression<Object>(otherValue, Object.class);
-        
-        assertFalse(expr.equals(otherExpr));
-    }
-    
-    @Test
-    public void testNotEqualsWrongClass() {
-        assertFalse(expr.equals(new Object()));
-    }
-    
-    @Test
-    public void testNotEqualsNull() {
-        assertFalse(expr.equals(null));
-    }
-    
-    @Test
-    public void testHashCode() {
-        assertEquals(VALUES.hashCode() + Object.class.hashCode(), expr.hashCode());
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/query/UnaryExpressionTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012-2017 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.query;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Before;
-import org.junit.Test;
-
-
-public class UnaryExpressionTest {
-    
-    private Expression operand;
-    private UnaryOperator operator;
-    private UnaryExpression<Expression, UnaryOperator> expr;
-
-    @Before
-    public void setup() {
-        operand = mock(Expression.class);
-        operator = mock(UnaryOperator.class);
-        expr = new UnaryExpression<Expression, UnaryOperator>(
-                operand, operator) {
-        };
-    }
-    
-    @Test
-    public void testGetOperand() {
-        assertEquals(operand, expr.getOperand());
-    }
-    
-    @Test
-    public void testGetOperator() {
-        assertEquals(operator, expr.getOperator());
-    }
-    
-    @Test
-    public void testEquals() {
-        UnaryExpression<Expression, UnaryOperator> otherExpr = new UnaryExpression<Expression, UnaryOperator>(
-                operand, operator) {
-        };
-        assertEquals(expr, otherExpr);
-    }
-    
-    @Test
-    public void testNotEquals() {
-        Expression otherOperand = mock(Expression.class);
-        UnaryExpression<Expression, UnaryOperator> otherExpr = new UnaryExpression<Expression, UnaryOperator>(
-                otherOperand, operator) {
-        };
-        
-        assertFalse(expr.equals(otherExpr));
-    }
-    
-    @Test
-    public void testNotEqualsWrongClass() {
-        assertFalse(expr.equals(new Object()));
-    }
-    
-    @Test
-    public void testNotEqualsNull() {
-        assertFalse(expr.equals(null));
-    }
-    
-    @Test
-    public void testHashCode() {
-        int hashCode = operator.hashCode() + operand.hashCode();
-        assertEquals(hashCode, expr.hashCode());
-    }
-
-}
-
--- a/storage/pom.xml	Fri May 19 11:37:45 2017 +0200
+++ b/storage/pom.xml	Fri May 19 11:58:05 2017 +0200
@@ -60,7 +60,6 @@
 
   <modules>
     <module>core</module>
-    <module>testutils</module>
   </modules>
 
 </project>
--- a/storage/testutils/pom.xml	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <groupId>com.redhat.thermostat</groupId>
-    <artifactId>thermostat-storage</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-  
-  <artifactId>thermostat-storage-testutils</artifactId>
-  <!-- Intentionally not a bundle. This module
-       provides utilities for testing statement
-       descriptors outside of storage-core -->
-  <packaging>jar</packaging>
-
-  <name>Thermostat Storage Test Utils</name>
-
-  <dependencies>
-    <!-- Uses classes from storage-core -->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-storage-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <!-- Intentionally not scope "test" since this utility uses mockito for
-         stubbing in src/main/java. However, this test utility
-         should only be used as a dep with scope "test". -->
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-    </dependency>
-  </dependencies>
-
-</project>
-
--- a/storage/testutils/src/main/java/com/redhat/thermostat/storage/internal/statement/DescriptorParserImplFactory.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-import com.redhat.thermostat.storage.core.BackingStorage;
-import com.redhat.thermostat.storage.core.Category;
-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.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Update;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.testutils.ParserType;
-
-class DescriptorParserImplFactory {
-    
-    <T extends Pojo> StatementDescriptorParser<T> getParser(ParserType type, StatementDescriptor<T> desc) {
-        switch (type) {
-        case BASIC:
-            return new BasicDescriptorParser<>(getBasicBackingStorage(), desc);
-        case SEMANTIC:
-            return new SemanticsEnabledDescriptorParser<>(getSemanticBackingStorage(desc.getDescriptor()), desc);
-        default:
-            throw new IllegalStateException("Not implemented");
-        }
-    }
-    
-    private BackingStorage getBasicBackingStorage() {
-        return mock(BackingStorage.class);
-    }
-    
-    @SuppressWarnings("unchecked")
-    private BackingStorage getSemanticBackingStorage(String desc) {
-        BackingStorage storage = mock(BackingStorage.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(mock(Add.class));
-        when(storage.createUpdate(any(Category.class))).thenReturn(mock(Update.class));
-        when(storage.createRemove(any(Category.class))).thenReturn(mock(Remove.class));
-        when(storage.createReplace(any(Category.class))).thenReturn(mock(Replace.class));
-        when(storage.createQuery(any(Category.class))).thenReturn(mock(Query.class));
-
-        AggregateQuery aggregateQuery = mock(AggregateQuery.class);
-        if (desc.contains("QUERY-COUNT")) {
-            when(aggregateQuery.getAggregateFunction()).thenReturn(AggregateFunction.COUNT);
-        } else {
-            when(aggregateQuery.getAggregateFunction()).thenReturn(AggregateFunction.DISTINCT);
-        }
-        when(storage.createAggregateQuery(any(AggregateFunction.class), any(Category.class))).thenReturn(aggregateQuery);
-        return storage;
-    }
-}
--- a/storage/testutils/src/main/java/com/redhat/thermostat/storage/internal/statement/TestParser.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012-2017 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.internal.statement;
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.testutils.ParserType;
-import com.redhat.thermostat.storage.testutils.StatementDescriptorTester;
-
-/**
- * Do NOT use this class directly. Use {@link StatementDescriptorTester} instead.
- */
-public final class TestParser<T extends Pojo> implements StatementDescriptorParser<T> {
-
-    private final StatementDescriptor<T> desc;
-    private final DescriptorParserImplFactory factory;
-    private final ParserType type;
-    
-    public TestParser(StatementDescriptor<T> desc, ParserType type) {
-        this.desc = desc;
-        this.factory = new DescriptorParserImplFactory();
-        this.type = type;
-    }
-    
-    @Override
-    public ParsedStatement<T> parse() throws DescriptorParsingException {
-        StatementDescriptorParser<T> actualParser = factory.getParser(type, desc);
-        actualParser.parse();
-        return null; // Always return null. Testing utility only.
-    }
-
-}
--- a/storage/testutils/src/main/java/com/redhat/thermostat/storage/testutils/ParserType.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012-2017 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.testutils;
-
-public enum ParserType {
-    BASIC,
-    SEMANTIC
-}
\ No newline at end of file
--- a/storage/testutils/src/main/java/com/redhat/thermostat/storage/testutils/StatementDescriptorTester.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2017 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.testutils;
-
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.internal.statement.TestParser;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/**
- * Unit test utility which is useful for verifying statement descriptors parse
- * correctly. 
- * 
- * @param <T> The underlying {@link Pojo} implementation type.
- */
-public final class StatementDescriptorTester<T extends Pojo> {
-
-    public void testParseBasic(StatementDescriptor<T> desc)
-            throws DescriptorParsingException {
-        TestParser<T> testParser = new TestParser<>(desc, ParserType.BASIC);
-        testParser.parse();
-    }
-    
-    public void testParseSemantic(StatementDescriptor<T> desc) throws DescriptorParsingException {
-        TestParser<T> testParser = new TestParser<>(desc, ParserType.SEMANTIC);
-        testParser.parse();
-    }
-}
--- a/storage/testutils/src/main/java/com/redhat/thermostat/storage/testutils/package-info.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright 2012-2017 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.
- */
-
-
-/**
- * Helpers for writing unit tests for storage-related classes.
- * <p>
- * This is for building only, not at run-time.
- */
-package com.redhat.thermostat.storage.testutils;
--- a/storage/testutils/src/test/java/com/redhat/thermostat/storage/testutils/StatementDescriptorTesterTest.java	Fri May 19 11:37:45 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012-2017 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.testutils;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-
-public class StatementDescriptorTesterTest {
-
-    private static final Key<String> barKey = new Key<>("bar");
-    private static final Category<TestPojo> testCategory = new Category<>("desc-tester-category", TestPojo.class, barKey);
-    
-    @Test(expected = DescriptorParsingException.class)
-    public void canDetermineBadDescriptorBasic() throws DescriptorParsingException {
-        String brokenDesc = "foo";
-        StatementDescriptor<TestPojo> desc = new StatementDescriptor<>(testCategory, brokenDesc);
-        StatementDescriptorTester<TestPojo> tester = new StatementDescriptorTester<>();
-        tester.testParseBasic(desc); // should throw exception
-    }
-    
-    public void canDetermineGoodDescriptorBasic() throws DescriptorParsingException {
-        // This desc has correct syntax, but is semantically incorrect. The
-        // basic parser does not check this though.
-        String goodDesc = "QUERY desc-tester-category WHERE 'foo' = ?l";
-        StatementDescriptor<TestPojo> desc = new StatementDescriptor<>(testCategory, goodDesc);
-        StatementDescriptorTester<TestPojo> tester = new StatementDescriptorTester<>();
-        tester.testParseBasic(desc); // must not throw exception
-    }
-    
-    @Test(expected = DescriptorParsingException.class)
-    public void canDetermineBadDescriptorSemantic() throws DescriptorParsingException {
-        // No such key 'foo' in category. Thus, DPE on parse()
-        String brokenDesc = "ADD desc-tester-category SET 'foo' = ?l";
-        StatementDescriptor<TestPojo> desc = new StatementDescriptor<>(testCategory, brokenDesc);
-        StatementDescriptorTester<TestPojo> tester = new StatementDescriptorTester<>();
-        tester.testParseSemantic(desc); // should throw exception
-    }
-    
-    @Test
-    public void canDetermineGoodDescriptorSemantic() throws DescriptorParsingException {
-        String goodDesc = "ADD desc-tester-category SET 'bar' = ?l";
-        StatementDescriptor<TestPojo> desc = new StatementDescriptor<>(testCategory, goodDesc);
-        StatementDescriptorTester<TestPojo> tester = new StatementDescriptorTester<>();
-        tester.testParseSemantic(desc); // must not throw exception
-    }
-    
-    static class TestPojo implements Pojo {
-        // empty
-    }
-}