changeset 1168:b6722888e6b3

Add generics for prepared statements This commit adds generic type parameters to several places dealing with prepared statements. This for instance allows us to have compile-time type checking of the Category used in these objects, and aligns with the type parameter used by Query. I have added support for a long free parameter in the grammar, since this will be needed to handle timestamps. This commit also converts StatementDescriptor from an interface to a class, taking the Pojo type as a type parameter. This will reduce code duplication since the implementation will not change from one DAO to another, so we would end up with multiple identical implementations. I have also added a getter for the StatementDescriptor in PreparedStatement. This will prove useful in logging errors, when only the PreparedStatement is available. I have also converted the remaining query in AgentInfoDAOImpl into a prepared statement, and logged the exceptions caused during parse/execution errors. Another small change is changing the operator field in BinaryExpressionNode to an Operator type, and using the field directly instead of calling the getter in createExpression. I have also cleaned up some raw types in tests related to prepared statements. Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-July/007302.html
author Elliott Baron <ebaron@redhat.com>
date Mon, 15 Jul 2013 12:51:42 -0400
parents 94e5078418e5
children 340d6f755eb7
files storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.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/Query.java storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.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/Storage.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.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/ParsedStatement.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/StatementDescriptorParser.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementTest.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/StatementDescriptorParserTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressionsTest.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java
diffstat 20 files changed, 390 insertions(+), 400 deletions(-) [+]
line wrap: on
line diff
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java	Mon Jul 15 12:51:42 2013 -0400
@@ -1,12 +1,14 @@
 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 extends Statement {
+public interface DataModifyingStatement<T extends Pojo> extends Statement<T> {
 
     /**
      * Executes this statement.
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatement.java	Mon Jul 15 12:51:42 2013 -0400
@@ -11,7 +11,7 @@
  * @see Storage#prepareStatement(StatementDescriptor)
  *
  */
-public interface PreparedStatement {
+public interface PreparedStatement<T extends Pojo> {
     
     void setBoolean(int paramIndex, boolean paramValue);
     
@@ -41,7 +41,7 @@
      * @throws StatementExecutionException
      *             If the prepared statement wasn't valid for execution.
      */
-    <T extends Pojo> Cursor<T> executeQuery() throws StatementExecutionException;
+    Cursor<T> executeQuery() throws StatementExecutionException;
     
     /**
      * 
@@ -49,4 +49,9 @@
      *         {@link Storage}.
      */
     int getId();
+    
+    /**
+     * @return the {@link StatementDescriptor} that describes this statement.
+     */
+    StatementDescriptor<T> getDescriptor();
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementFactory.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedStatementFactory.java	Mon Jul 15 12:51:42 2013 -0400
@@ -1,6 +1,7 @@
 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}.
@@ -8,11 +9,11 @@
  */
 public class PreparedStatementFactory {
 
-    public static PreparedStatement getInstance(Storage storage,
-            StatementDescriptor desc) throws DescriptorParsingException {
+    public static <T extends Pojo> PreparedStatement<T> getInstance(Storage 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);
+        return new PreparedStatementImpl<>(storage, desc);
     }
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java	Mon Jul 15 12:51:42 2013 -0400
@@ -42,7 +42,7 @@
 /**
  * Describes what data should be fetched.
  */
-public interface Query<T extends Pojo> extends Statement {
+public interface Query<T extends Pojo> extends Statement<T> {
 
     enum SortDirection {
         ASCENDING(1),
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Mon Jul 15 12:51:42 2013 -0400
@@ -269,7 +269,7 @@
     }
     
     @Override
-    public PreparedStatement prepareStatement(final StatementDescriptor desc)
+    public <T extends Pojo> PreparedStatement<T> prepareStatement(final StatementDescriptor<T> desc)
             throws DescriptorParsingException {
         return delegate.prepareStatement(desc);
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Statement.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Statement.java	Mon Jul 15 12:51:42 2013 -0400
@@ -1,10 +1,12 @@
 package com.redhat.thermostat.storage.core;
 
+import com.redhat.thermostat.storage.model.Pojo;
+
 /**
  * Marker interface for all operations on storage. This includes queries and
  * statements manipulating data.
  *
  */
-public interface Statement {
+public interface Statement<T extends Pojo> {
 
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/StatementDescriptor.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/StatementDescriptor.java	Mon Jul 15 12:51:42 2013 -0400
@@ -1,6 +1,16 @@
 package com.redhat.thermostat.storage.core;
 
-public interface StatementDescriptor {
+import com.redhat.thermostat.storage.model.Pojo;
+
+public class StatementDescriptor<T extends Pojo> {
+    
+    private Category<T> category;
+    private String desc;
+    
+    public StatementDescriptor(Category<T> category, String desc) {
+        this.category = category;
+        this.desc = desc;
+    }
 
     /**
      * Describes this statement for preparation. For example:
@@ -11,8 +21,12 @@
      * 
      * @return The statement descriptor.
      */
-    String getQueryDescriptor();
+    public String getQueryDescriptor() {
+        return desc;
+    }
     
-    Category<?> getCategory();
+    public Category<T> getCategory() {
+        return category;
+    }
     
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Mon Jul 15 12:51:42 2013 -0400
@@ -64,7 +64,7 @@
      *         something Storage knows about, {@code null} otherwise.
      * @throws DescriptorParsingException If the descriptor string was invalid.
      */
-    PreparedStatement prepareStatement(StatementDescriptor desc)
+    <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc)
             throws DescriptorParsingException;
 
     /**
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Jul 15 12:51:42 2013 -0400
@@ -39,17 +39,16 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
 import com.redhat.thermostat.storage.core.Put;
-import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
@@ -69,7 +68,7 @@
     public AgentInfoDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(CATEGORY);
-        factory = new ExpressionFactory();
+        this.factory = new ExpressionFactory();
     }
 
     @Override
@@ -80,19 +79,19 @@
     @Override
     public List<AgentInformation> getAllAgentInformation() {
         String allAgentsQuery = "QUERY " + CATEGORY.getName();
-        AgentInformationDescriptor desc = new AgentInformationDescriptor(CATEGORY, allAgentsQuery);
-        PreparedStatement prepared = null;
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, allAgentsQuery);
+        PreparedStatement<AgentInformation> prepared = null;
         Cursor<AgentInformation> agentCursor = null;
         try {
             prepared = storage.prepareStatement(desc);
             agentCursor = prepared.executeQuery();
         } catch (DescriptorParsingException e) {
             // should not happen, but if it *does* happen, at least log it
-            logger.severe("Preparing query '" + desc + "' failed!");
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
             return Collections.emptyList();
         } catch (StatementExecutionException e) {
             // should not happen, but if it *does* happen, at least log it
-            logger.severe("Executing query '" + desc + "' failed!");
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
             return Collections.emptyList();
         }
         List<AgentInformation> results = new ArrayList<>();
@@ -108,8 +107,8 @@
     public List<AgentInformation> getAliveAgents() {
         // QUERY agent-config WHERE ? = true
         String allAgentsQuery = "QUERY " + CATEGORY.getName() + " WHERE ?s = ?b";
-        AgentInformationDescriptor desc = new AgentInformationDescriptor(CATEGORY, allAgentsQuery);
-        PreparedStatement prepared = null;
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, allAgentsQuery);
+        PreparedStatement<AgentInformation> prepared = null;
         Cursor<AgentInformation> agentCursor = null;
         try {
             prepared = storage.prepareStatement(desc);
@@ -118,11 +117,11 @@
             agentCursor = prepared.executeQuery();
         } catch (DescriptorParsingException e) {
             // should not happen, but if it *does* happen, at least log it
-            logger.severe("Preparing query '" + desc + "' failed!");
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
             return Collections.emptyList();
         } catch (StatementExecutionException e) {
             // should not happen, but if it *does* happen, at least log it
-            logger.severe("Executing query '" + desc + "' failed!");
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
             return Collections.emptyList();
         }
         List<AgentInformation> results = new ArrayList<>();
@@ -136,11 +135,30 @@
 
     @Override
     public AgentInformation getAgentInformation(HostRef agentRef) {
-        Query<AgentInformation> query = storage.createQuery(CATEGORY);
-        Expression expr = factory.equalTo(Key.AGENT_ID, agentRef.getAgentId());
-        query.where(expr);
-        query.limit(1);
-        return query.execute().next();
+        String query = "QUERY " + CATEGORY.getName() + " WHERE ?s = ?s";
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(CATEGORY, query);
+        PreparedStatement<AgentInformation> prepared;
+        Cursor<AgentInformation> agentCursor;
+        try {
+            prepared = storage.prepareStatement(desc);
+            prepared.setString(0, Key.AGENT_ID.getName());
+            prepared.setString(1, agentRef.getAgentId());
+            agentCursor = prepared.executeQuery();
+        } catch (DescriptorParsingException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e);
+            return null;
+        } catch (StatementExecutionException e) {
+            // should not happen, but if it *does* happen, at least log it
+            logger.log(Level.SEVERE, "Executing query '" + desc + "' failed!", e);
+            return null;
+        }
+        
+        AgentInformation result = null;
+        if (agentCursor.hasNext()) {
+            result = agentCursor.next();
+        }
+        return result;
     }
 
     @Override
@@ -169,32 +187,5 @@
         update.apply();
     }
     
-    private static class AgentInformationDescriptor implements StatementDescriptor {
-        
-        private final Category<AgentInformation> category;
-        private final String desc;
-        
-        private AgentInformationDescriptor(Category<AgentInformation> cat, String desc) {
-            this.category = cat;
-            this.desc = desc;
-        }
-        
-        @Override
-        public Category<?> getCategory() {
-            return category;
-        }
-
-        @Override
-        public String getQueryDescriptor() {
-            return desc;
-        }
-        
-        @Override
-        public String toString() {
-            return getClass().getSimpleName() + " " + desc;
-        }
-        
-    }
-
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/BinaryExpressionNode.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/BinaryExpressionNode.java	Mon Jul 15 12:51:42 2013 -0400
@@ -45,19 +45,19 @@
 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 Object operator;
+    private Operator operator;
 
-    public Object getOperator() {
+    public Operator getOperator() {
         return operator;
     }
 
-    public void setOperator(Object operator) {
+    public void setOperator(Operator operator) {
         this.operator = operator;
     }
 
@@ -99,13 +99,10 @@
 
     private PatchedWhereExpression createExpression(Expression leftExpression,
             Expression rightExpression) {
-        assert( getOperator() != null );
-        if (getOperator() instanceof BinaryComparisonOperator) {
-            BinaryComparisonOperator op = (BinaryComparisonOperator)getOperator();
-            return getBinaryComparisonExpression(leftExpression, op, rightExpression);
-        } else if (getOperator() instanceof BinaryLogicalOperator) {
-            BinaryLogicalOperator op = (BinaryLogicalOperator)getOperator();
-            return getBinaryLogicalExpression(leftExpression, op, rightExpression);
+        if (operator instanceof BinaryComparisonOperator) {
+            return getBinaryComparisonExpression(leftExpression, (BinaryComparisonOperator) operator, rightExpression);
+        } else if (operator instanceof BinaryLogicalOperator) {
+            return getBinaryLogicalExpression(leftExpression, (BinaryLogicalOperator) operator, rightExpression);
         }
         return null;
     }
@@ -117,9 +114,9 @@
         return new PatchedWhereExpressionImpl(impl);
     }
 
-    @SuppressWarnings({ "unchecked" }) // Unchecked casts to LiteralExpression
+    @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<Key<T>> leftOperand = (LiteralExpression<Key<T>>) a;
         LiteralExpression<T> rightOperand = (LiteralExpression<T>)b;
         BinaryComparisonExpression<T> impl = new BinaryComparisonExpression<>(
                 leftOperand, op, rightOperand);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/ParsedStatement.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/ParsedStatement.java	Mon Jul 15 12:51:42 2013 -0400
@@ -38,6 +38,7 @@
 
 import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Statement;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
 /**
@@ -47,13 +48,13 @@
  *
  * @see PreparedStatementImpl#executeQuery()
  */
-class ParsedStatement {
+class ParsedStatement<T extends Pojo> {
 
     private int numParams;
     private SuffixExpression suffixExpn;
-    private final Statement statement;
+    private final Statement<T> statement;
     
-    ParsedStatement(Statement statement) {
+    ParsedStatement(Statement<T> statement) {
         this.statement = statement;
     }
     
@@ -61,11 +62,11 @@
         return numParams;
     }
 
-    public Statement getRawStatement() {
+    public Statement<T> getRawStatement() {
         return statement;
     }
     
-    public Statement patchQuery(PreparedStatementImpl stmt) throws IllegalPatchException {
+    public Statement<T> patchQuery(PreparedStatementImpl<T> stmt) throws IllegalPatchException {
         if (suffixExpn == null) {
             String msg = "Suffix expression must be set before patching!";
             IllegalStateException expn = new IllegalStateException(msg);
@@ -87,8 +88,8 @@
             return;
         }
         PatchedLimitExpression patchedExp = expn.patch(params);
-        if (statement instanceof Query<?>) {
-            Query<?> query = (Query<?>)statement;
+        if (statement instanceof Query) {
+            Query<T> query = (Query<T>) statement;
             query.limit(patchedExp.getLimitValue());
         } else {
             String msg = "Patching of non-query types not (yet) supported! Class was:"
@@ -105,8 +106,8 @@
             return;
         }
         PatchedSortExpression patchedExp = expn.patch(params);
-        if (statement instanceof Query<?>) {
-            Query<?> query = (Query<?>)statement;
+        if (statement instanceof Query) {
+            Query<T> query = (Query<T>) statement;
             PatchedSortMember[] members = patchedExp.getSortMembers();
             for (int i = 0; i < members.length; i++) {
                 query.sort(members[i].getSortKey(), members[i].getDirection());
@@ -129,8 +130,8 @@
         // the way.
         PatchedWhereExpression patchedExp = expn.patch(params);
         Expression whereClause = patchedExp.getExpression();
-        if (statement instanceof Query<?>) {
-            Query<?> query = (Query<?>)statement;
+        if (statement instanceof Query) {
+            Query<T> query = (Query<T>) statement;
             query.where(whereClause);
         } else {
             String msg = "Patching of non-query types not (yet) supported! Class was:"
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Mon Jul 15 12:51:42 2013 -0400
@@ -51,23 +51,25 @@
  * Main implementation of {@link PreparedStatement}s.
  *
  */
-final public class PreparedStatementImpl implements PreparedStatement {
+final public class PreparedStatementImpl<T extends Pojo> implements PreparedStatement<T> {
     
-    private Query<? extends Pojo> query;
-    private DataModifyingStatement dmlStatement;
+    private StatementDescriptor<T> desc;
+    private Query<T> query;
+    private DataModifyingStatement<T> dmlStatement;
     private final PreparedParameter[] params;
-    private final ParsedStatement parsedStatement;
+    private final ParsedStatement<T> parsedStatement;
     
-    public PreparedStatementImpl(Storage storage, StatementDescriptor desc) throws DescriptorParsingException {
-        StatementDescriptorParser parser = new StatementDescriptorParser(storage, desc);
+    public PreparedStatementImpl(Storage storage, StatementDescriptor<T> desc) throws DescriptorParsingException {
+        this.desc = desc;
+        StatementDescriptorParser<T> parser = new StatementDescriptorParser<>(storage, desc);
         this.parsedStatement = parser.parse();
         int numParams = parsedStatement.getNumParams();
         params = new PreparedParameter[numParams];
-        Statement statement = parsedStatement.getRawStatement();
+        Statement<T> statement = parsedStatement.getRawStatement();
         if (statement instanceof DataModifyingStatement) {
-            this.dmlStatement = (DataModifyingStatement)statement;
-        } else if (statement instanceof Query<?>) {
-            this.query = (Query<?>)statement;
+            this.dmlStatement = (DataModifyingStatement<T>) statement;
+        } else if (statement instanceof Query) {
+            this.query = (Query<T>) statement;
         }
     }
     
@@ -113,17 +115,15 @@
                             + DataModifyingStatement.class.getName());
         }
         try {
-            dmlStatement = (DataModifyingStatement)parsedStatement.patchQuery(this);
+            dmlStatement = (DataModifyingStatement<T>) parsedStatement.patchQuery(this);
         } catch (Exception e) {
             throw new StatementExecutionException(e);
         }
         return dmlStatement.execute();
     }
 
-    // unchecked since query has no knowledge of type
-    @SuppressWarnings("unchecked")
     @Override
-    public Cursor<?> executeQuery() throws StatementExecutionException{
+    public Cursor<T> executeQuery() throws StatementExecutionException{
         if (query == null) {
             throw new IllegalStateException(
                     "Can't execute statement which isn't an instance of "
@@ -133,7 +133,7 @@
             // 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<?>)parsedStatement.patchQuery(this);
+            query = (Query<T>) parsedStatement.patchQuery(this);
         } catch (IllegalPatchException e) {
             throw new StatementExecutionException(e);
         }
@@ -154,4 +154,9 @@
     PreparedParameter[] getParams() {
         return params;
     }
+
+    @Override
+    public StatementDescriptor<T> getDescriptor() {
+        return desc;
+    }
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Mon Jul 15 12:51:42 2013 -0400
@@ -44,9 +44,10 @@
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
 import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
 
@@ -78,11 +79,12 @@
  * condition     := 'NOT' condition | compExp
  * compExp       := term compExpRHS
  * term          := freeParam | literal
- * freeParam     := '?s' | '?i' | '?s[' | '?b'
- * literal       := sQuote string sQuote | int | boolean
+ * 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;
  * string        := &lt;literal-string-value&gt;
  * compExpRHS    := '=' term | '&lt;=' term | '&gt;=' term | '&lt;' term | '&gt;' term
  * </pre>
@@ -98,7 +100,7 @@
  * 
  * NOTE: Comparison expressions have equal precedence.
  */
-class StatementDescriptorParser {
+class StatementDescriptorParser<T extends Pojo> {
 
     private static final String TOKEN_DELIMS = " \t\r\n\f";
     private static final String[] KNOWN_STATEMENT_TYPES = new String[] {
@@ -113,15 +115,15 @@
     private static final char PARAM_PLACEHOLDER = '?';
     
     private final String[] tokens;
-    private final StatementDescriptor desc;
+    private final StatementDescriptor<T> desc;
     private final Storage storage;
     private int currTokenIndex;
     private int placeHolderCount;
     // the parsed statement
-    private ParsedStatement parsedStatement;
+    private ParsedStatement<T> parsedStatement;
     private SuffixExpression tree;
     
-    StatementDescriptorParser(Storage storage, StatementDescriptor desc) {
+    StatementDescriptorParser(Storage storage, StatementDescriptor<T> desc) {
         this.tokens = getTokens(desc.getQueryDescriptor());
         this.currTokenIndex = 0;
         this.placeHolderCount = 0;
@@ -138,7 +140,7 @@
         return toks.toArray(new String[0]);
     }
 
-    public ParsedStatement parse() throws DescriptorParsingException {
+    public ParsedStatement<T> parse() throws DescriptorParsingException {
         matchStatementType();
         matchCategory();
         // matched so far, create the raw statement
@@ -457,7 +459,7 @@
             // illegal type
             return null;
         }
-        assert(term.equals("i") || term.equals("s") || term.equals("s[") || term.equals("b"));
+        assert(term.equals("i") || term.equals("l") || term.equals("s") || term.equals("s[") || term.equals("b"));
         char switchChar = term.charAt(0);
         Class<?> type = null;
         switch (switchChar) {
@@ -465,6 +467,10 @@
             type = Integer.class;
             break;
         }
+        case 'l': {
+            type = Long.class;
+            break;
+        }
         case 's': {
             if (term.length() == 1) {
                 type = String.class;
@@ -564,8 +570,8 @@
     private void createStatement() {
         if (tokens[0].equals(KNOWN_STATEMENT_TYPES[0])) {
             // query case
-            Query<?> query = storage.createQuery(desc.getCategory());
-            this.parsedStatement = new ParsedStatement(query);
+            Query<T> query = storage.createQuery(desc.getCategory());
+            this.parsedStatement = new ParsedStatement<>(query);
         } else {
             throw new IllegalStateException("Don't know how to create statement type '" + tokens[0] + "'");
         }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Jul 15 12:51:42 2013 -0400
@@ -58,7 +58,6 @@
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
@@ -96,7 +95,7 @@
 
     @Test
     public void verifyCategoryName() {
-        Category category = AgentInfoDAO.CATEGORY;
+        Category<AgentInformation> category = AgentInfoDAO.CATEGORY;
         assertEquals("agent-config", category.getName());
     }
 
@@ -120,17 +119,18 @@
         assertTrue(keys.contains(AgentInfoDAO.CONFIG_LISTEN_ADDRESS));
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Test
     public void verifyGetAllAgentInformationWithOneAgentInStorage()
             throws DescriptorParsingException, StatementExecutionException {
-        Cursor agentCursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<AgentInformation> agentCursor = (Cursor<AgentInformation>) mock(Cursor.class);
         when(agentCursor.hasNext()).thenReturn(true).thenReturn(false);
         when(agentCursor.next()).thenReturn(agent1).thenReturn(null);
 
         Storage storage = mock(Storage.class);
-        PreparedStatement stmt = mock(PreparedStatement.class);
-        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
         when(stmt.executeQuery()).thenReturn(agentCursor);
         AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage);
 
@@ -142,26 +142,29 @@
         AgentInformation expected = agentInfo1;
         assertEquals(expected, result);
     }
+    
+    @SuppressWarnings("unchecked")
+    private StatementDescriptor<AgentInformation> anyDescriptor() {
+        return (StatementDescriptor<AgentInformation>) any(StatementDescriptor.class);
+    }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Test
     public void verifyGetAliveAgent() throws DescriptorParsingException, StatementExecutionException {
-        Cursor agentCursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        Cursor<AgentInformation> agentCursor = (Cursor<AgentInformation>) mock(Cursor.class);
         when(agentCursor.hasNext()).thenReturn(true).thenReturn(false);
         when(agentCursor.next()).thenReturn(agent1).thenReturn(null);
 
-        Query query = mock(Query.class);
         Storage storage = mock(Storage.class);
-        PreparedStatement stmt = mock(PreparedStatement.class);
-        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
         when(stmt.executeQuery()).thenReturn(agentCursor);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        when(query.execute()).thenReturn(agentCursor);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
         List<AgentInformation> aliveAgents = dao.getAliveAgents();
 
-        verify(storage).prepareStatement(any(StatementDescriptor.class));
+        verify(storage).prepareStatement(anyDescriptor());
         verify(stmt).executeQuery();
         verify(stmt).setString(eq(0), eq(AgentInfoDAOImpl.ALIVE_KEY.getName()));
         verify(stmt).setBoolean(eq(1), eq(true));
@@ -175,17 +178,18 @@
     }
 
     @Test
-    public void verifyGetAgentInformationWhenStorageCantFindIt() {
+    public void verifyGetAgentInformationWhenStorageCantFindIt() throws DescriptorParsingException, StatementExecutionException {
         HostRef agentRef = mock(HostRef.class);
 
-        Query query = mock(Query.class);
-        Cursor cursor = mock(Cursor.class);
+        Storage storage = mock(Storage.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        Cursor<AgentInformation> cursor = (Cursor<AgentInformation>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(false);
         when(cursor.next()).thenReturn(null);
-        when(query.execute()).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
+        when(stmt.executeQuery()).thenReturn(cursor);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
@@ -195,27 +199,28 @@
     }
 
     @Test
-    public void verifyGetAgentInformation() {
+    public void verifyGetAgentInformation() throws StatementExecutionException, DescriptorParsingException {
         HostRef agentRef = mock(HostRef.class);
         when(agentRef.getAgentId()).thenReturn(agentInfo1.getAgentId());
 
         Storage storage = mock(Storage.class);
-        Query query = mock(Query.class);
-        when(storage.createQuery(any(Category.class))).thenReturn(query);
-        Cursor cursor = mock(Cursor.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class);
+        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
+        @SuppressWarnings("unchecked")
+        Cursor<AgentInformation> cursor = (Cursor<AgentInformation>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(agentInfo1).thenReturn(null);
-        when(query.execute()).thenReturn(cursor);
+        when(stmt.executeQuery()).thenReturn(cursor);
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
         AgentInformation computed = dao.getAgentInformation(agentRef);
 
-        verify(storage).createQuery(AgentInfoDAO.CATEGORY);
-        Expression expr = factory.equalTo(Key.AGENT_ID, agentInfo1.getAgentId());
-        verify(query).where(eq(expr));
-        verify(query).limit(1);
-        verify(query).execute();
-        verifyNoMoreInteractions(query);
+        verify(storage).prepareStatement(anyDescriptor());
+        verify(stmt).setString(0, Key.AGENT_ID.getName());
+        verify(stmt).setString(1, agentInfo1.getAgentId());
+        verify(stmt).executeQuery();
+        verifyNoMoreInteractions(stmt);
         AgentInformation expected = agentInfo1;
         assertSame(expected, computed);
     }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementTest.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementTest.java	Mon Jul 15 12:51:42 2013 -0400
@@ -52,6 +52,7 @@
 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.model.Pojo;
 import com.redhat.thermostat.storage.query.BinaryComparisonExpression;
 import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
 import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
@@ -61,7 +62,7 @@
 
 public class ParsedStatementTest {
 
-    private Query<?> statement;
+    private Query<Pojo> statement;
     
     @Before
     public void setup() {
@@ -73,11 +74,10 @@
         statement = null;
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void canPatchWhereAndExpr() throws IllegalPatchException {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         suffixExpn.setLimitExpn(null);
         suffixExpn.setSortExpn(null);
@@ -93,7 +93,7 @@
         and.setLeftChild(leftEqual);
         and.setRightChild(rightEqual);
         TerminalNode a = new TerminalNode(leftEqual);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         TerminalNode b = new TerminalNode(leftEqual);
         UnfinishedValueNode patchB = new UnfinishedValueNode();
@@ -116,41 +116,40 @@
         parsedStmt.setSuffixExpression(suffixExpn);
         // next, create the PreparedStatement we are going to use for
         // patching.
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(2);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
         preparedStatement.setString(0, "test1");
         preparedStatement.setInt(1, 2);
         // finally test the patching
-        Query<?> query = (Query)parsedStmt.patchQuery(preparedStatement);
+        Query<Pojo> query = (Query<Pojo>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         TestQuery q = (TestQuery)query;
         Expression expectedExpression = q.expr;
         assertTrue(expectedExpression instanceof BinaryLogicalExpression);
-        BinaryLogicalExpression andFinal = (BinaryLogicalExpression)expectedExpression;
+        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();
+        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();
+        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();
+        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());
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void canPatchBasicWhereEquals() throws IllegalPatchException {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         suffixExpn.setLimitExpn(null);
         suffixExpn.setSortExpn(null);
@@ -160,7 +159,7 @@
         expn.getRoot().setValue(and);
         and.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode a = new TerminalNode(and);
-        a.setValue(new Key("a", false));
+        a.setValue(new Key<>("a", false));
         TerminalNode b = new TerminalNode(and);
         UnfinishedValueNode bPatch = new UnfinishedValueNode();
         bPatch.setParameterIndex(0);
@@ -173,46 +172,45 @@
         parsedStmt.setSuffixExpression(suffixExpn);
         // next, create the PreparedStatement we are going to use for
         // patching.
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(1);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
         preparedStatement.setBoolean(0, true);
         // finally test the patching
-        Query<?> query = (Query)parsedStmt.patchQuery(preparedStatement);
+        Query<?> query = (Query<?>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         TestQuery q = (TestQuery)query;
         Expression expectedExpression = q.expr;
         assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        BinaryComparisonExpression root = (BinaryComparisonExpression)expectedExpression;
+        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", false), leftLiteral1.getValue());
+        LiteralExpression<?> leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
+        LiteralExpression<?> rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
+        assertEquals(new Key<>("a", false), 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 = new PreparedStatementImpl<>(1);
         preparedStatement.setBoolean(0, false);
-        query = (Query)parsedStmt.patchQuery(preparedStatement);
+        query = (Query<?>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         q = (TestQuery)query;
         expectedExpression = q.expr;
         assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        root = (BinaryComparisonExpression)expectedExpression;
+        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", false), leftLiteral1.getValue());
+        leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
+        rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
+        assertEquals(new Key<>("a", false), leftLiteral1.getValue());
         assertEquals(false, rightLiteral1.getValue());
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void canPatchBasicWhereEqualsLHSKeyAndRHSValue() throws IllegalPatchException {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         suffixExpn.setLimitExpn(null);
         suffixExpn.setSortExpn(null);
@@ -239,47 +237,47 @@
         parsedStmt.setSuffixExpression(suffixExpn);
         // next, create the PreparedStatement we are going to use for
         // patching.
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(2);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
         preparedStatement.setString(0, "a");
         preparedStatement.setBoolean(1, true);
         // finally test the patching
-        Query<?> query = (Query)parsedStmt.patchQuery(preparedStatement);
+        Query<?> query = (Query<?>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         TestQuery q = (TestQuery)query;
         Expression expectedExpression = q.expr;
         assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        BinaryComparisonExpression root = (BinaryComparisonExpression)expectedExpression;
+        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", false), leftLiteral1.getValue());
+        LiteralExpression<?> leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
+        LiteralExpression<?> rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
+        assertEquals(new Key<>("a", false), 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 = new PreparedStatementImpl<>(2);
         preparedStatement.setString(0, "a");
         preparedStatement.setBoolean(1, false);
-        query = (Query)parsedStmt.patchQuery(preparedStatement);
+        query = (Query<?>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         q = (TestQuery)query;
         expectedExpression = q.expr;
         assertTrue(expectedExpression instanceof BinaryComparisonExpression);
-        root = (BinaryComparisonExpression)expectedExpression;
+        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", false), leftLiteral1.getValue());
+        leftLiteral1 = (LiteralExpression<?>)root.getLeftOperand();
+        rightLiteral1 = (LiteralExpression<?>)root.getRightOperand();
+        assertEquals(new Key<>("a", false), leftLiteral1.getValue());
         assertEquals(false, rightLiteral1.getValue());
     }
     
     @Test
     public void canPatchBasicLimit() throws IllegalPatchException {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         LimitExpression limitExpnToPatch = new LimitExpression();
         UnfinishedLimitValue unfinished = new UnfinishedLimitValue();
@@ -290,20 +288,18 @@
         suffixExpn.setWhereExpn(null);
         parsedStmt.setSuffixExpression(suffixExpn);
         // set the value for the one unfinished param
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(1);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
         preparedStatement.setInt(0, 3);
-        @SuppressWarnings("rawtypes")
-        Query query = (Query)parsedStmt.patchQuery(preparedStatement);
+        Query<?> query = (Query<?>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         TestQuery q = (TestQuery)query;
         assertEquals(3, q.limitVal);
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void canPatchBasicSort() throws IllegalPatchException {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         // SORT ? ASC, b DSC
         SortExpression sortExpn = new SortExpression();
@@ -322,30 +318,29 @@
         suffixExpn.setWhereExpn(null);
         parsedStmt.setSuffixExpression(suffixExpn);
         // set the value for the one unfinished param
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(1);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
         preparedStatement.setString(0, "a");
-        Query query = (Query)parsedStmt.patchQuery(preparedStatement);
+        Query<Pojo> query = (Query<Pojo>)parsedStmt.patchQuery(preparedStatement);
         assertTrue(query instanceof TestQuery);
         TestQuery q = (TestQuery)query;
-        List<Pair<Key, SortDirection>> actualSorts = q.sorts;
+        List<Pair<Key<?>, SortDirection>> actualSorts = q.sorts;
         assertEquals(2, actualSorts.size());
-        Pair first = actualSorts.get(0);
-        Key firstKeyActual = (Key)first.getFirst();
-        Key expectedFirst = new Key("a", false);
+        Pair<Key<?>, SortDirection> first = actualSorts.get(0);
+        Key<?> firstKeyActual = (Key<?>)first.getFirst();
+        Key<?> expectedFirst = new Key<>("a", false);
         assertEquals(expectedFirst, firstKeyActual);
         assertEquals(SortDirection.ASCENDING, first.getSecond());
-        Pair second = actualSorts.get(1);
-        Key secondKeyActual = (Key)second.getFirst();
-        Key expectedSecond = new Key("b", false);
+        Pair<Key<?>, SortDirection> second = actualSorts.get(1);
+        Key<?> secondKeyActual = (Key<?>)second.getFirst();
+        Key<?> expectedSecond = new Key<>("b", false);
         assertEquals(expectedSecond, secondKeyActual);
         assertEquals(SortDirection.DESCENDING, second.getSecond());
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void failPatchWithWrongType() throws IllegalPatchException {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         suffixExpn.setLimitExpn(null);
         suffixExpn.setSortExpn(null);
@@ -361,7 +356,7 @@
         and.setLeftChild(leftEqual);
         and.setRightChild(rightEqual);
         TerminalNode a = new TerminalNode(leftEqual);
-        Key aKey = new Key("a", false);
+        Key<?> aKey = new Key<>("a", false);
         a.setValue(aKey);
         TerminalNode b = new TerminalNode(leftEqual);
         UnfinishedValueNode patchB = new UnfinishedValueNode();
@@ -371,7 +366,7 @@
         leftEqual.setLeftChild(a);
         leftEqual.setRightChild(b);
         TerminalNode c = new TerminalNode(rightEqual);
-        Key cKey = new Key("c", false);
+        Key<?> cKey = new Key<>("c", false);
         c.setValue(cKey);
         rightEqual.setLeftChild(c);
         TerminalNode d = new TerminalNode(rightEqual);
@@ -385,7 +380,7 @@
         parsedStmt.setSuffixExpression(suffixExpn);
         // next, create the PreparedStatement we are going to use for
         // patching.
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(2);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(2);
         preparedStatement.setString(0, "test1");
         preparedStatement.setString(1, "foo");
         // finally test the patching
@@ -401,7 +396,7 @@
     @Test
     public void failPatchBasicEqualsIfIndexOutofBounds() {
         // create the parsedStatementImpl we are going to use
-        ParsedStatement parsedStmt = new ParsedStatement(statement);
+        ParsedStatement<Pojo> parsedStmt = new ParsedStatement<>(statement);
         SuffixExpression suffixExpn = new SuffixExpression();
         suffixExpn.setLimitExpn(null);
         suffixExpn.setSortExpn(null);
@@ -421,7 +416,7 @@
         suffixExpn.setWhereExpn(expn);
         parsedStmt.setNumFreeParams(1);
         parsedStmt.setSuffixExpression(suffixExpn);
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(1);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(1);
         preparedStatement.setString(0, "b");
         // this should fail
         try {
@@ -432,11 +427,10 @@
         }
     }
     
-    @SuppressWarnings("rawtypes")
-    private static class TestQuery implements Query {
+    private static class TestQuery implements Query<Pojo> {
 
         private Expression expr;
-        private List<Pair<Key, SortDirection>> sorts;
+        private List<Pair<Key<?>, SortDirection>> sorts;
         private int limitVal = -1;
         
         private TestQuery() {
@@ -449,8 +443,8 @@
         }
 
         @Override
-        public void sort(Key key, SortDirection direction) {
-            Pair<Key, SortDirection> sortPair = new Pair<>(key, direction);
+        public void sort(Key<?> key, SortDirection direction) {
+            Pair<Key<?>, SortDirection> sortPair = new Pair<Key<?>, SortDirection>(key, direction);
             sorts.add(sortPair);
         }
 
@@ -460,7 +454,7 @@
         }
 
         @Override
-        public Cursor execute() {
+        public Cursor<Pojo> execute() {
             // Not implemented
             return null;
         }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImplTest.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImplTest.java	Mon Jul 15 12:51:42 2013 -0400
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -52,6 +51,7 @@
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.BinaryComparisonExpression;
 import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
 import com.redhat.thermostat.storage.query.Expression;
@@ -61,7 +61,7 @@
 
     @Test
     public void failToSetIndexOutOfBounds() {
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(2);
+        PreparedStatementImpl<?> preparedStatement = new PreparedStatementImpl<>(2);
         preparedStatement.setInt(1, 3);
         preparedStatement.setString(0, "testing");
         try {
@@ -90,42 +90,44 @@
         }
     }
     
-    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Test
     public void canDoParsingPatchingAndExecution() throws Exception {
         String queryString = "QUERY foo WHERE 'a' = ?s";
-        StatementDescriptor desc = mock(StatementDescriptor.class);
+        @SuppressWarnings("unchecked")
+        StatementDescriptor<Pojo> desc = (StatementDescriptor<Pojo>) mock(StatementDescriptor.class);
         when(desc.getQueryDescriptor()).thenReturn(queryString);
-        Category mockCategory = mock(Category.class);
+        @SuppressWarnings("unchecked")
+        Category<Pojo> mockCategory = (Category<Pojo>) mock(Category.class);
         when(desc.getCategory()).thenReturn(mockCategory);
         when(mockCategory.getName()).thenReturn("foo");
         Storage storage = mock(Storage.class);
         StubQuery stmt = new StubQuery();
-        when(storage.createQuery(any(Category.class))).thenReturn(stmt);
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(storage, desc);
+        when(storage.createQuery(mockCategory)).thenReturn(stmt);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(storage, desc);
         preparedStatement.setString(0, "foo");
         preparedStatement.executeQuery();
         assertTrue(stmt.called);
-        LiteralExpression o1 = new LiteralExpression<>(new Key("a", false));
-        LiteralExpression o2 = new LiteralExpression<>("foo"); 
-        BinaryComparisonExpression<LiteralExpression> binComp = new BinaryComparisonExpression<LiteralExpression>(
+        LiteralExpression<Key<String>> o1 = new LiteralExpression<>(new Key<String>("a", false));
+        LiteralExpression<String> o2 = new LiteralExpression<>("foo"); 
+        BinaryComparisonExpression<String> binComp = new BinaryComparisonExpression<>(
                 o1, BinaryComparisonOperator.EQUALS, o2);
         assertEquals(binComp, stmt.expr);
     }
     
-    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Test
     public void failExecutionWithWronglyTypedParams() throws Exception {
         String queryString = "QUERY foo WHERE 'a' = ?b";
-        StatementDescriptor desc = mock(StatementDescriptor.class);
+        @SuppressWarnings("unchecked")
+        StatementDescriptor<Pojo> desc = (StatementDescriptor<Pojo>) mock(StatementDescriptor.class);
         when(desc.getQueryDescriptor()).thenReturn(queryString);
-        Category mockCategory = mock(Category.class);
+        @SuppressWarnings("unchecked")
+        Category<Pojo> mockCategory = (Category<Pojo>) mock(Category.class);
         when(desc.getCategory()).thenReturn(mockCategory);
         when(mockCategory.getName()).thenReturn("foo");
         Storage storage = mock(Storage.class);
         StubQuery stmt = new StubQuery();
-        when(storage.createQuery(any(Category.class))).thenReturn(stmt);
-        PreparedStatementImpl preparedStatement = new PreparedStatementImpl(storage, desc);
+        when(storage.createQuery(mockCategory)).thenReturn(stmt);
+        PreparedStatementImpl<Pojo> preparedStatement = new PreparedStatementImpl<>(storage, desc);
         preparedStatement.setString(0, "foo");
         try {
             preparedStatement.executeQuery();
@@ -136,8 +138,7 @@
         }
     }
     
-    @SuppressWarnings("rawtypes")
-    private static class StubQuery implements Query {
+    private static class StubQuery implements Query<Pojo> {
 
         private Expression expr;
         private boolean called = false;
@@ -148,7 +149,7 @@
         }
 
         @Override
-        public void sort(Key key, SortDirection direction) {
+        public void sort(Key<?> key, SortDirection direction) {
             // nothing
         }
 
@@ -158,7 +159,7 @@
         }
 
         @Override
-        public Cursor execute() {
+        public Cursor<Pojo> execute() {
             called = true;
             return null;
         }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java	Mon Jul 15 12:51:42 2013 -0400
@@ -51,36 +51,22 @@
 import org.junit.Before;
 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.Query;
+import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.internal.statement.BinaryExpressionNode;
-import com.redhat.thermostat.storage.internal.statement.LimitExpression;
-import com.redhat.thermostat.storage.internal.statement.NotBooleanExpressionNode;
-import com.redhat.thermostat.storage.internal.statement.ParsedStatement;
-import com.redhat.thermostat.storage.internal.statement.SortExpression;
-import com.redhat.thermostat.storage.internal.statement.SortMember;
-import com.redhat.thermostat.storage.internal.statement.StatementDescriptorParser;
-import com.redhat.thermostat.storage.internal.statement.SuffixExpression;
-import com.redhat.thermostat.storage.internal.statement.TerminalNode;
-import com.redhat.thermostat.storage.internal.statement.UnfinishedLimitValue;
-import com.redhat.thermostat.storage.internal.statement.UnfinishedSortKey;
-import com.redhat.thermostat.storage.internal.statement.UnfinishedValueNode;
-import com.redhat.thermostat.storage.internal.statement.WhereExpression;
+import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.query.BinaryComparisonOperator;
 import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
 
 public class StatementDescriptorParserTest {
 
     private Storage storage;
-    @SuppressWarnings("rawtypes")
-    private Query mockQuery;
-    private StatementDescriptorParser parser;
+    private Query<AgentInformation> mockQuery;
+    private StatementDescriptorParser<AgentInformation> parser;
     
     @SuppressWarnings("unchecked")
     @Before
@@ -99,9 +85,9 @@
     @Test
     public void testParseQuerySimple() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName();
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = (ParsedStatement)parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = (ParsedStatement<AgentInformation>)parser.parse();
         assertEquals(0, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression tree = statement.getSuffixExpression();
@@ -113,9 +99,9 @@
     @Test
     public void testParseQuerySimpleWithLimit() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT ?i";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = (ParsedStatement)parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = (ParsedStatement<AgentInformation>)parser.parse();
         assertEquals(1, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression expn = statement.getSuffixExpression();
@@ -131,9 +117,9 @@
     @Test
     public void testParseSortMultiple() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " SORT 'a' ASC , 'b' DSC , 'c' ASC";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = (ParsedStatement)parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = (ParsedStatement<AgentInformation>)parser.parse();
         assertEquals(0, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression suffixExpn = statement.getSuffixExpression();
@@ -152,13 +138,12 @@
         assertEquals("c", list.get(2).getSortKey());
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void testParseQueryWithMultipleConcunctions() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' AND 'c' = 'd' AND 'e' < ?i";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = parser.parse();
         assertEquals(1, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression expn = statement.getSuffixExpression();
@@ -178,7 +163,7 @@
         and2.setLeftChild(equality1);
         equality1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode a = new TerminalNode(equality1);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         equality1.setLeftChild(a);
         TerminalNode b = new TerminalNode(equality1);
@@ -188,7 +173,7 @@
         and2.setRightChild(equality2);
         equality2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode c = new TerminalNode(equality2);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality2.setLeftChild(c);
         TerminalNode d = new TerminalNode(equality2);
@@ -198,7 +183,7 @@
         lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
         and1.setRightChild(lessThan);
         TerminalNode e = new TerminalNode(lessThan);
-        Key eKey = new Key("e", false);
+        Key<Integer> eKey = new Key<>("e", false);
         e.setValue(eKey);
         lessThan.setLeftChild(e);
         UnfinishedValueNode f = new UnfinishedValueNode();
@@ -212,13 +197,12 @@
         assertTrue( WhereExpressions.equals(expected, where));
     }
     
-    @SuppressWarnings("rawtypes")
     @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 desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = parser.parse();
         assertEquals(0, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression expn = statement.getSuffixExpression();
@@ -241,7 +225,7 @@
         and3.setLeftChild(equality1);
         equality1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode a = new TerminalNode(equality1);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         equality1.setLeftChild(a);
         TerminalNode b = new TerminalNode(equality1);
@@ -251,7 +235,7 @@
         and3.setRightChild(equality2);
         equality2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode c = new TerminalNode(equality2);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality2.setLeftChild(c);
         TerminalNode d = new TerminalNode(equality2);
@@ -261,7 +245,7 @@
         lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
         and2.setRightChild(lessThan);
         TerminalNode e = new TerminalNode(lessThan);
-        Key eKey = new Key("e", false);
+        Key<String> eKey = new Key<>("e", false);
         e.setValue(eKey);
         lessThan.setLeftChild(e);
         TerminalNode f = new TerminalNode(lessThan);
@@ -270,7 +254,7 @@
         BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(and1);
         greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
         TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key gKey = new Key("g", false);
+        Key<String> gKey = new Key<>("g", false);
         g.setValue(gKey);
         greaterOrEqual.setLeftChild(g);
         TerminalNode h = new TerminalNode(greaterOrEqual);
@@ -281,13 +265,12 @@
         assertTrue( WhereExpressions.equals(expected, where));
     }
     
-    @SuppressWarnings("rawtypes")
     @Test
     public void testParseQueryWithMultipleDisjunctions() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = 'b' OR 'c' = 'd' OR 'e' < ?i";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = parser.parse();
         assertEquals(1, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression expn = statement.getSuffixExpression();
@@ -308,7 +291,7 @@
         or2.setLeftChild(equality1);
         equality1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode a = new TerminalNode(equality1);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         equality1.setLeftChild(a);
         TerminalNode b = new TerminalNode(equality1);
@@ -318,7 +301,7 @@
         or2.setRightChild(equality2);
         equality2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode c = new TerminalNode(equality2);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality2.setLeftChild(c);
         TerminalNode d = new TerminalNode(equality2);
@@ -328,7 +311,7 @@
         lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
         or1.setRightChild(lessThan);
         TerminalNode e = new TerminalNode(lessThan);
-        Key eKey = new Key("e", false);
+        Key<Integer> eKey = new Key<>("e", false);
         e.setValue(eKey);
         lessThan.setLeftChild(e);
         UnfinishedValueNode f = new UnfinishedValueNode();
@@ -342,13 +325,12 @@
         assertTrue( WhereExpressions.equals(expected, where));
     }
     
-    @SuppressWarnings("rawtypes")
     @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 desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = parser.parse();
         assertEquals(0, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression expn = statement.getSuffixExpression();
@@ -372,7 +354,7 @@
         or3.setLeftChild(equality1);
         equality1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode a = new TerminalNode(equality1);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         equality1.setLeftChild(a);
         TerminalNode b = new TerminalNode(equality1);
@@ -382,7 +364,7 @@
         or3.setRightChild(equality2);
         equality2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode c = new TerminalNode(equality2);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality2.setLeftChild(c);
         TerminalNode d = new TerminalNode(equality2);
@@ -392,7 +374,7 @@
         lessThan.setOperator(BinaryComparisonOperator.LESS_THAN);
         or2.setRightChild(lessThan);
         TerminalNode e = new TerminalNode(lessThan);
-        Key eKey = new Key("e", false);
+        Key<String> eKey = new Key<>("e", false);
         e.setValue(eKey);
         lessThan.setLeftChild(e);
         TerminalNode f = new TerminalNode(lessThan);
@@ -401,7 +383,7 @@
         BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(or1);
         greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
         TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key gKey = new Key("g", false);
+        Key<String> gKey = new Key<>("g", false);
         g.setValue(gKey);
         greaterOrEqual.setLeftChild(g);
         TerminalNode h = new TerminalNode(greaterOrEqual);
@@ -412,13 +394,12 @@
         assertTrue( WhereExpressions.equals(expected, where));
     }
     
-    @SuppressWarnings("rawtypes")
     @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 desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = parser.parse();
         assertEquals(0, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression expn = statement.getSuffixExpression();
@@ -439,7 +420,7 @@
         BinaryExpressionNode equality3 = new BinaryExpressionNode(and1);
         equality3.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode x = new TerminalNode(equality3);
-        x.setValue(new Key("x", false));
+        x.setValue(new Key<>("x", false));
         TerminalNode y = new TerminalNode(equality3);
         y.setValue("y");
         equality3.setLeftChild(x);
@@ -451,7 +432,7 @@
         equality4.setOperator(BinaryComparisonOperator.EQUALS);
         and2.setRightChild(equality4);
         TerminalNode u = new TerminalNode(equality4);
-        u.setValue(new Key("u", false));
+        u.setValue(new Key<>("u", false));
         equality4.setLeftChild(u);
         TerminalNode w = new TerminalNode(equality4);
         w.setValue("w");
@@ -459,7 +440,7 @@
         BinaryExpressionNode equality5 = new BinaryExpressionNode(and3);
         equality5.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode s = new TerminalNode(equality5);
-        s.setValue(new Key("s", false));
+        s.setValue(new Key<>("s", false));
         TerminalNode t = new TerminalNode(equality5);
         t.setValue("t");
         equality5.setLeftChild(s);
@@ -477,7 +458,7 @@
         or1.setLeftChild(equality1);
         equality1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode a = new TerminalNode(equality1);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         equality1.setLeftChild(a);
         TerminalNode b = new TerminalNode(equality1);
@@ -487,7 +468,7 @@
         equality2.setOperator(BinaryComparisonOperator.EQUALS);
         or1.setRightChild(equality2);
         TerminalNode c = new TerminalNode(equality2);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality2.setLeftChild(c);
         TerminalNode d = new TerminalNode(equality2);
@@ -498,7 +479,7 @@
         or2.setRightChild(lessThan);
         or2.setLeftChild(or1);
         TerminalNode e = new TerminalNode(lessThan);
-        Key eKey = new Key("e", false);
+        Key<String> eKey = new Key<>("e", false);
         e.setValue(eKey);
         lessThan.setLeftChild(e);
         TerminalNode f = new TerminalNode(lessThan);
@@ -507,7 +488,7 @@
         BinaryExpressionNode greaterOrEqual = new BinaryExpressionNode(or3);
         greaterOrEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
         TerminalNode g = new TerminalNode(greaterOrEqual);
-        Key gKey = new Key("g", false);
+        Key<String> gKey = new Key<>("g", false);
         g.setValue(gKey);
         greaterOrEqual.setLeftChild(g);
         TerminalNode h = new TerminalNode(greaterOrEqual);
@@ -520,13 +501,12 @@
         assertTrue(WhereExpressions.equals(expected, where));
     }
     
-    @SuppressWarnings("rawtypes")
     @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 desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = (ParsedStatement)parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = (ParsedStatement<AgentInformation>) parser.parse();
         assertEquals(2, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression suffixExpn = statement.getSuffixExpression();
@@ -555,7 +535,7 @@
         BinaryExpressionNode unequality = new BinaryExpressionNode(and);
         unequality.setOperator(BinaryComparisonOperator.LESS_THAN);
         TerminalNode a = new TerminalNode(unequality);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         unequality.setLeftChild(a);
         TerminalNode b = new TerminalNode(unequality);
@@ -565,7 +545,7 @@
         BinaryExpressionNode equality = new BinaryExpressionNode(and);
         equality.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode c = new TerminalNode(equality);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality.setLeftChild(c);
         UnfinishedValueNode patch1 = new UnfinishedValueNode();
@@ -580,7 +560,7 @@
         not.setValue(greaterEqual);
         greaterEqual.setOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL_TO);
         TerminalNode x = new TerminalNode(greaterEqual);
-        Key xKey = new Key("x", false);
+        Key<Integer> xKey = new Key<>("x", false);
         x.setValue(xKey);
         greaterEqual.setLeftChild(x);
         UnfinishedValueNode patch2 = new UnfinishedValueNode();
@@ -594,13 +574,12 @@
         assertTrue( WhereExpressions.equals(where, suffixExpn.getWhereExpn()));
     }
     
-    @SuppressWarnings("rawtypes")
     @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 desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = (ParsedStatement)parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = (ParsedStatement<AgentInformation>) parser.parse();
         assertEquals(2, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression suffixExpn = statement.getSuffixExpression();
@@ -627,7 +606,7 @@
         BinaryExpressionNode unequality = new BinaryExpressionNode(or);
         unequality.setOperator(BinaryComparisonOperator.LESS_THAN);
         TerminalNode a = new TerminalNode(unequality);
-        Key aKey = new Key("a", false);
+        Key<String> aKey = new Key<>("a", false);
         a.setValue(aKey);
         unequality.setLeftChild(a);
         TerminalNode b = new TerminalNode(unequality);
@@ -637,7 +616,7 @@
         BinaryExpressionNode equality = new BinaryExpressionNode(or);
         equality.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode c = new TerminalNode(equality);
-        Key cKey = new Key("c", false);
+        Key<String> cKey = new Key<>("c", false);
         c.setValue(cKey);
         equality.setLeftChild(c);
         UnfinishedValueNode patch1 = new UnfinishedValueNode();
@@ -654,9 +633,9 @@
     @Test
     public void testParseQuerySimpleWhereAndSimpleSort() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' < 'b' SORT 'a' DSC";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = (ParsedStatement)parser.parse();
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = (ParsedStatement<AgentInformation>)parser.parse();
         assertEquals(0, statement.getNumParams());
         assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
         SuffixExpression suffixExpn = statement.getSuffixExpression();
@@ -688,11 +667,11 @@
     @Test
     public void testParseQuerySimpleWithOneWhere() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE '" + Key.AGENT_ID.getName() + "' = ?s";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = null; 
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = null; 
         try {
-            statement = (ParsedStatement)parser.parse();
+            statement = (ParsedStatement<AgentInformation>)parser.parse();
         } catch (DescriptorParsingException e) {
             fail(e.getMessage());
         }
@@ -727,8 +706,8 @@
     public void testParseSimpleWithAndOr() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE '" + Key.AGENT_ID.getName() + "' = ?s" +
                             " AND ?s < ?b OR 'a' = 'b'";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         ParsedStatement statement = null; 
         try {
             statement = (ParsedStatement)parser.parse();
@@ -797,11 +776,11 @@
     @Test
     public void testParseSimpleWithAnd() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?s AND ?s = 'd'";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = null; 
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = null; 
         try {
-            statement = (ParsedStatement)parser.parse();
+            statement = (ParsedStatement<AgentInformation>)parser.parse();
         } catch (DescriptorParsingException e) {
             e.printStackTrace();
             fail(e.getMessage());
@@ -851,11 +830,11 @@
     @Test
     public void testParseSimpleWithNotOR() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE NOT 'a' = ?s OR ?s = 'd'";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = null; 
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = null; 
         try {
-            statement = (ParsedStatement)parser.parse();
+            statement = (ParsedStatement<AgentInformation>)parser.parse();
         } catch (DescriptorParsingException e) {
             e.printStackTrace();
             fail(e.getMessage());
@@ -907,11 +886,11 @@
     @Test
     public void testParseSimpleWithOr() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?s OR ?s = 'd'";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = null; 
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = null; 
         try {
-            statement = (ParsedStatement)parser.parse();
+            statement = (ParsedStatement<AgentInformation>)parser.parse();
         } catch (DescriptorParsingException e) {
             e.printStackTrace();
             fail(e.getMessage());
@@ -961,11 +940,11 @@
     @Test
     public void testParseSimpleWithLimit() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT 1";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
-        ParsedStatement statement = null; 
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatement<AgentInformation> statement = null; 
         try {
-            statement = (ParsedStatement)parser.parse();
+            statement = (ParsedStatement<AgentInformation>)parser.parse();
         } catch (DescriptorParsingException e) {
             e.printStackTrace();
             fail(e.getMessage());
@@ -982,8 +961,8 @@
     @Test
     public void rejectLimitWhichIsNotInt() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT illegal";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -994,8 +973,8 @@
     @Test
     public void rejectLHSnotString() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE a < 1";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1006,10 +985,10 @@
     
     @Test
     public void rejectIllegalFreeParamType() throws DescriptorParsingException {
-        // ? should be one of '?i', '?s', '?b', '?s['
+        // ? should be one of '?i', '?l', '?s', '?b', '?s['
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE ? < 1";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1021,8 +1000,8 @@
     @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 desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1034,8 +1013,8 @@
     @Test
     public void rejectParseQueryWhereBoolTerm() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE true AND false";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1047,8 +1026,8 @@
     public void rejectSimpleQueryWithMissingSpaces() throws DescriptorParsingException {
         // we require a space before every operator/keyword
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY + " WHERE " + "'a'='b'";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1060,8 +1039,8 @@
     public void rejectSimpleQueryWithMissingSpaces2() throws DescriptorParsingException {
         // we require a space before every operator/keyword
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY + " WHERE " + "'a' ='b'";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1073,8 +1052,8 @@
     public void rejectSimpleQueryWithInvalidComparison() throws DescriptorParsingException {
         // <> is illegal
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY + " WHERE " + "'a' <> 'b'";
-        StatementDescriptor desc = getDescriptor(descrString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
         } catch (DescriptorParsingException e) {
@@ -1085,8 +1064,8 @@
     @Test
     public void rejectInvalidDescriptorStringBadWhere() throws DescriptorParsingException {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " where '" + Key.AGENT_ID.getName() + "'= ?s";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
             fail("lower case where not allowed in descriptor. Should have rejected.");
@@ -1099,8 +1078,8 @@
     @Test
     public void rejectInvalidDescriptorStringBadStatementType() throws DescriptorParsingException {
         String descString = "UNKNOWN some-unknown-category WHERE 1 = ?i";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
             fail("UNKNOWN not a valid statement type");
@@ -1113,8 +1092,8 @@
     @Test
     public void rejectInvalidDescriptorStringCategoryMismatch() throws DescriptorParsingException {
         String descString = "QUERY some-unknown-category WHERE 1 = ?i";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
             fail("category names in descriptor and Category object did not match!");
@@ -1127,8 +1106,8 @@
     @Test
     public void rejectInvalidDescriptorStringBadSortNoArg() throws DescriptorParsingException {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' = ?i SORT";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
             fail("category names in descriptor and Category object did not match!");
@@ -1141,8 +1120,8 @@
     @Test
     public void rejectInvalidDescriptorStringBadWhereNoArg() throws DescriptorParsingException {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE SORT";
-        StatementDescriptor desc = getDescriptor(descString, AgentInfoDAO.CATEGORY);
-        parser = new StatementDescriptorParser(storage, desc);
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
+        parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
             fail("category names in descriptor and Category object did not match!");
@@ -1153,18 +1132,4 @@
         }
     }
     
-    private StatementDescriptor getDescriptor(final String desc, final Category<?> category) {
-        return new StatementDescriptor() {
-            
-            @Override
-            public String getQueryDescriptor() {
-                return desc;
-            }
-            
-            @Override
-            public Category<?> getCategory() {
-                return category;
-            }
-        };
-    }
 }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressionsTest.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/WhereExpressionsTest.java	Mon Jul 15 12:51:42 2013 -0400
@@ -45,6 +45,8 @@
 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 {
 
@@ -92,7 +94,7 @@
         WhereExpression expn1 = new WhereExpression();
         BinaryExpressionNode binNode1 = new BinaryExpressionNode(expn1.getRoot());
         expn1.getRoot().setValue(binNode1);
-        binNode1.setOperator("OR");
+        binNode1.setOperator(BinaryLogicalOperator.OR);
         NotBooleanExpressionNode notNode1 = new NotBooleanExpressionNode(binNode1);
         TerminalNode termNode1 = new TerminalNode(notNode1);
         termNode1.setValue("testing");
@@ -100,9 +102,9 @@
         binNode1.setLeftChild(notNode1);
         BinaryExpressionNode and1 = new BinaryExpressionNode(binNode1);
         binNode1.setRightChild(and1);
-        and1.setOperator("AND");
+        and1.setOperator(BinaryLogicalOperator.AND);
         BinaryExpressionNode left1 = new BinaryExpressionNode(and1);
-        left1.setOperator("=");
+        left1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode termNode1Equal = new TerminalNode(left1);
         termNode1Equal.setValue("a");
         TerminalNode termNode1EqualOther = new TerminalNode(left1);
@@ -111,7 +113,7 @@
         left1.setRightChild(termNode1EqualOther);
         and1.setLeftChild(left1);
         BinaryExpressionNode right1 = new BinaryExpressionNode(and1);
-        right1.setOperator("<=");
+        right1.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
         TerminalNode termNode1LessEqual = new TerminalNode(right1);
         termNode1LessEqual.setValue("x");
         TerminalNode termNode1LessEqualOther = new TerminalNode(right1);
@@ -124,7 +126,7 @@
         WhereExpression expn2 = new WhereExpression();
         BinaryExpressionNode binNode2 = new BinaryExpressionNode(expn2.getRoot());
         expn2.getRoot().setValue(binNode2);
-        binNode2.setOperator("OR");
+        binNode2.setOperator(BinaryLogicalOperator.OR);
         NotBooleanExpressionNode notNode2 = new NotBooleanExpressionNode(binNode2);
         TerminalNode termNode2 = new TerminalNode(notNode2);
         termNode2.setValue("testing");
@@ -132,9 +134,9 @@
         binNode2.setLeftChild(notNode2);
         BinaryExpressionNode and2 = new BinaryExpressionNode(binNode2);
         binNode2.setRightChild(and2);
-        and2.setOperator("AND");
+        and2.setOperator(BinaryLogicalOperator.AND);
         BinaryExpressionNode left2 = new BinaryExpressionNode(and2);
-        left2.setOperator("=");
+        left2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode termNode2Equal = new TerminalNode(left2);
         termNode2Equal.setValue("a");
         TerminalNode termNode2EqualOther = new TerminalNode(left2);
@@ -143,7 +145,7 @@
         left2.setRightChild(termNode2EqualOther);
         and2.setLeftChild(left2);
         BinaryExpressionNode right2 = new BinaryExpressionNode(and2);
-        right2.setOperator("<=");
+        right2.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
         TerminalNode termNode2LessEqual = new TerminalNode(right2);
         termNode2LessEqual.setValue("x");
         TerminalNode termNode2LessEqualOther = new TerminalNode(right2);
@@ -159,7 +161,7 @@
         WhereExpression expn1 = new WhereExpression();
         BinaryExpressionNode binNode1 = new BinaryExpressionNode(expn1.getRoot());
         expn1.getRoot().setValue(binNode1);
-        binNode1.setOperator("OR");
+        binNode1.setOperator(BinaryLogicalOperator.OR);
         NotBooleanExpressionNode notNode1 = new NotBooleanExpressionNode(binNode1);
         TerminalNode termNode1 = new TerminalNode(notNode1);
         termNode1.setValue("testing");
@@ -167,9 +169,9 @@
         binNode1.setLeftChild(notNode1);
         BinaryExpressionNode and1 = new BinaryExpressionNode(binNode1);
         binNode1.setRightChild(and1);
-        and1.setOperator("AND");
+        and1.setOperator(BinaryLogicalOperator.AND);
         BinaryExpressionNode left1 = new BinaryExpressionNode(and1);
-        left1.setOperator("=");
+        left1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode termNode1Equal = new TerminalNode(left1);
         termNode1Equal.setValue("d"); // should be "a" to make it equal
         TerminalNode termNode1EqualOther = new TerminalNode(left1);
@@ -178,7 +180,7 @@
         left1.setRightChild(termNode1EqualOther);
         and1.setLeftChild(left1);
         BinaryExpressionNode right1 = new BinaryExpressionNode(and1);
-        right1.setOperator("<=");
+        right1.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
         TerminalNode termNode1LessEqual = new TerminalNode(right1);
         termNode1LessEqual.setValue("x");
         TerminalNode termNode1LessEqualOther = new TerminalNode(right1);
@@ -191,7 +193,7 @@
         WhereExpression expn2 = new WhereExpression();
         BinaryExpressionNode binNode2 = new BinaryExpressionNode(expn2.getRoot());
         expn2.getRoot().setValue(binNode2);
-        binNode2.setOperator("OR");
+        binNode2.setOperator(BinaryLogicalOperator.OR);
         NotBooleanExpressionNode notNode2 = new NotBooleanExpressionNode(binNode2);
         TerminalNode termNode2 = new TerminalNode(notNode2);
         termNode2.setValue("testing");
@@ -199,9 +201,9 @@
         binNode2.setLeftChild(notNode2);
         BinaryExpressionNode and2 = new BinaryExpressionNode(binNode2);
         binNode2.setRightChild(and2);
-        and2.setOperator("AND");
+        and2.setOperator(BinaryLogicalOperator.AND);
         BinaryExpressionNode left2 = new BinaryExpressionNode(and2);
-        left2.setOperator("=");
+        left2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode termNode2Equal = new TerminalNode(left2);
         termNode2Equal.setValue("a");
         TerminalNode termNode2EqualOther = new TerminalNode(left2);
@@ -210,7 +212,7 @@
         left2.setRightChild(termNode2EqualOther);
         and2.setLeftChild(left2);
         BinaryExpressionNode right2 = new BinaryExpressionNode(and2);
-        right2.setOperator("<=");
+        right2.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
         TerminalNode termNode2LessEqual = new TerminalNode(right2);
         termNode2LessEqual.setValue("x");
         TerminalNode termNode2LessEqualOther = new TerminalNode(right2);
@@ -226,7 +228,7 @@
         WhereExpression expn1 = new WhereExpression();
         BinaryExpressionNode binNode1 = new BinaryExpressionNode(expn1.getRoot());
         expn1.getRoot().setValue(binNode1);
-        binNode1.setOperator("OR");
+        binNode1.setOperator(BinaryLogicalOperator.OR);
         NotBooleanExpressionNode notNode1 = new NotBooleanExpressionNode(binNode1);
         TerminalNode termNode1 = new TerminalNode(notNode1);
         termNode1.setValue("testing");
@@ -234,9 +236,9 @@
         binNode1.setLeftChild(notNode1);
         BinaryExpressionNode and1 = new BinaryExpressionNode(binNode1);
         binNode1.setRightChild(and1);
-        and1.setOperator("AND");
+        and1.setOperator(BinaryLogicalOperator.AND);
         BinaryExpressionNode left1 = new BinaryExpressionNode(and1);
-        left1.setOperator("=");
+        left1.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode termNode1Equal = new TerminalNode(left1);
         termNode1Equal.setValue("d"); // should be "a" to make it equal
         TerminalNode termNode1EqualOther = new TerminalNode(left1);
@@ -245,7 +247,7 @@
         left1.setRightChild(termNode1EqualOther);
         and1.setLeftChild(left1);
         BinaryExpressionNode right1 = new BinaryExpressionNode(and1);
-        right1.setOperator("<=");
+        right1.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
         TerminalNode termNode1LessEqual = new TerminalNode(right1);
         termNode1LessEqual.setValue("x");
         TerminalNode termNode1LessEqualOther = new TerminalNode(right1);
@@ -259,9 +261,9 @@
         NotBooleanExpressionNode notNode2 = new NotBooleanExpressionNode(expn2.getRoot());
         BinaryExpressionNode and2 = new BinaryExpressionNode(notNode2);
         notNode2.setValue(and2);
-        and2.setOperator("AND");
+        and2.setOperator(BinaryLogicalOperator.AND);
         BinaryExpressionNode left2 = new BinaryExpressionNode(and2);
-        left2.setOperator("=");
+        left2.setOperator(BinaryComparisonOperator.EQUALS);
         TerminalNode termNode2Equal = new TerminalNode(left2);
         termNode2Equal.setValue("a");
         TerminalNode termNode2EqualOther = new TerminalNode(left2);
@@ -270,7 +272,7 @@
         left2.setRightChild(termNode2EqualOther);
         and2.setLeftChild(left2);
         BinaryExpressionNode right2 = new BinaryExpressionNode(and2);
-        right2.setOperator("<=");
+        right2.setOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL_TO);
         TerminalNode termNode2LessEqual = new TerminalNode(right2);
         termNode2LessEqual.setValue("x");
         TerminalNode termNode2LessEqualOther = new TerminalNode(right2);
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Mon Jul 15 12:51:42 2013 -0400
@@ -337,7 +337,7 @@
     }
 
     @Override
-    public PreparedStatement prepareStatement(StatementDescriptor statementDesc)
+    public <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> statementDesc)
             throws DescriptorParsingException {
         // FIXME: Use some kind of cache in order to avoid parsing of
         // descriptors each time this is called. At least if the descriptor
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Mon Jul 15 14:14:34 2013 +0200
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Mon Jul 15 12:51:42 2013 -0400
@@ -102,7 +102,6 @@
 import com.redhat.thermostat.storage.core.Remove;
 import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.SecureStorage;
-import com.redhat.thermostat.storage.core.Statement;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.StorageException;
@@ -708,7 +707,7 @@
     }
 
     @Override
-    public PreparedStatement prepareStatement(StatementDescriptor desc)
+    public <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc)
             throws DescriptorParsingException {
         // TODO Implement
         return null;