changeset 1547:bc8f92a73f15

Compiler project for prepared statement - part III main patch review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-November/011554.html reviewed-by: omajid
author Mario Torre <neugens.limasoftware@gmail.com>
date Tue, 18 Nov 2014 16:03:34 +0100
parents 32255ddb2c4c
children 3f4f67db2177
files thread/collector/pom.xml thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategories.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoKeys.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/Descriptor.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/DescriptorBuilder.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptor.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorBuilder.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptor.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptorBuilder.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/SessionQuery.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/SummaryQuery.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapter.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapterBuilder.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Category.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/CategoryBuilder.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Criterion.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/FieldDescriptor.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Id.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Indexed.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/InsertEngine.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/LimitCriterion.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Query.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryEngine.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryValues.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/ResultHandler.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/SortCriterion.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Statement.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementEngine.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementUtils.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/TypeMapper.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Value.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/WhereCriterion.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/SessionID.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSession.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementBeanAdapterRegistrationTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategoriesTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/DescriptorTester.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorBuilderTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptorBuilderTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptorTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/SessionQueryTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/SummaryQueryTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapterBuilderTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapterTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/CategoryBuilderTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/DescriptorTester.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/InsertEngineTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryEngineTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryValuesTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementUtilsTest.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadSessionHelper.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.java
diffstat 59 files changed, 3892 insertions(+), 1273 deletions(-) [+]
line wrap: on
line diff
--- a/thread/collector/pom.xml	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/pom.xml	Tue Nov 18 16:03:34 2014 +0100
@@ -61,6 +61,7 @@
       <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
+
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-core</artifactId>
@@ -117,11 +118,12 @@
               com.redhat.thermostat.thread.collector,
               com.redhat.thermostat.thread.dao,
               com.redhat.thermostat.thread.model,
+              com.redhat.thermostat.thread.dao.impl.statement.support,
             </Export-Package>
             <Private-Package>
               com.redhat.thermostat.thread.common.osgi,
               com.redhat.thermostat.thread.dao.impl,
-              com.redhat.thermostat.thread.dao.impl.descriptor,
+              com.redhat.thermostat.thread.dao.impl.statement,
             </Private-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategories.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategories.java	Tue Nov 18 16:03:34 2014 +0100
@@ -38,14 +38,14 @@
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.Pojo;
+import com.redhat.thermostat.thread.dao.impl.statement.support.CategoryBuilder;
 import com.redhat.thermostat.thread.model.ThreadSession;
 import com.redhat.thermostat.thread.model.ThreadSummary;
-import java.lang.reflect.Field;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.logging.Level;
+import java.util.List;
 import java.util.logging.Logger;
 
 /**
@@ -55,58 +55,28 @@
 
     private static final Logger logger = LoggingUtils.getLogger(ThreadDaoCategories.class);
 
-    public static final Category<ThreadSummary> THREAD_SUMMARY =
-            new Category<>("vm-thread-summary", ThreadSummary.class,
-                           Arrays.<Key<?>>asList(
-                                   Key.AGENT_ID,
-                                   Key.VM_ID,
-                                   ThreadDaoKeys.SESSION,
-                                   Key.TIMESTAMP,
-                                   ThreadDaoKeys.LIVE_THREADS_KEY,
-                                   ThreadDaoKeys.DAEMON_THREADS_KEY),
-                           Arrays.<Key<?>>asList(Key.TIMESTAMP, ThreadDaoKeys.SESSION));
+    public static class Categories {
+        public static final String SUMMARY = "vm-thread-summary";
+        public static final String SESSION = "vm-thread-session";
+    }
 
-
-    public static final Category<ThreadSession> THREAD_SESSION =
-            new Category<>("vm-thread-session", ThreadSession.class,
-                           Arrays.<Key<?>>asList(
-                                   Key.AGENT_ID,
-                                   Key.VM_ID,
-                                   ThreadDaoKeys.SESSION,
-                                   Key.TIMESTAMP),
-                           Arrays.<Key<?>>asList(Key.TIMESTAMP, Key.VM_ID));
+    static final List<Class<? extends Pojo>> BEANS = new ArrayList<>();
+    static {
+        BEANS.add(ThreadSummary.class);
+        BEANS.add(ThreadSession.class);
+    }
 
     public static void register(Collection<String> collection) {
-        for (Field field : ThreadDaoCategories.class.getDeclaredFields()) {
-            field.setAccessible(true);
-            if (field.getType().isAssignableFrom(Category.class)) {
-                Category category = null;
-                try {
-                    category = (Category) field.get(null);
-                    collection.add(category.getName());
-
-                } catch (IllegalAccessException e) {
-                    logger.log(Level.SEVERE, "Error while registering categories...", e);
-                    throw new RuntimeException(e);
-                }
-            }
+        for (Class<? extends Pojo> beanClass: BEANS) {
+            Category<? extends Pojo> category = new CategoryBuilder(beanClass).build();
+            collection.add(category.getName());
         }
     }
 
     public static void register(Storage storage) {
-        for (Field field : ThreadDaoCategories.class.getDeclaredFields()) {
-            field.setAccessible(true);
-            if (field.getType().isAssignableFrom(Category.class)) {
-                Category category = null;
-                try {
-                    category = (Category) field.get(null);
-                    storage.registerCategory(category);
-
-                } catch (IllegalAccessException e) {
-                    logger.log(Level.SEVERE, "Error while registering categories...", e);
-                    throw new RuntimeException(e);
-                }
-            }
+        for (Class<? extends Pojo> beanClass: BEANS) {
+            Category<? extends Pojo> category = new CategoryBuilder(beanClass).build();
+            storage.registerCategory(category);
         }
     }
 }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Tue Nov 18 16:03:34 2014 +0100
@@ -49,10 +49,14 @@
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.thread.dao.ThreadDao;
-import com.redhat.thermostat.thread.dao.impl.descriptor.SummaryDescriptor;
-import com.redhat.thermostat.thread.dao.impl.descriptor.SummaryDescriptorBuilder;
-import com.redhat.thermostat.thread.dao.impl.descriptor.ThreadSessionDescriptor;
-import com.redhat.thermostat.thread.dao.impl.descriptor.ThreadSessionDescriptorBuilder;
+import com.redhat.thermostat.thread.dao.impl.statement.SessionQuery;
+import com.redhat.thermostat.thread.dao.impl.statement.SummaryQuery;
+import com.redhat.thermostat.thread.dao.impl.statement.support.BeanAdapter;
+import com.redhat.thermostat.thread.dao.impl.statement.support.BeanAdapterBuilder;
+
+import com.redhat.thermostat.thread.dao.impl.statement.support.Query;
+import com.redhat.thermostat.thread.dao.impl.statement.support.QueryValues;
+import com.redhat.thermostat.thread.dao.impl.statement.support.ResultHandler;
 import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadContentionSample;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
@@ -71,8 +75,8 @@
     
     private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class);
 
-    static final SummaryDescriptor SUMMARY = new SummaryDescriptorBuilder().build();
-    static final ThreadSessionDescriptor SESSIONS = new ThreadSessionDescriptorBuilder().build();
+    static final BeanAdapter<ThreadSummary> SUMMARY = new BeanAdapterBuilder<>(ThreadSummary.class, new SummaryQuery()).build();
+    static final BeanAdapter<ThreadSession> SESSIONS = new BeanAdapterBuilder<>(ThreadSession.class, new SessionQuery()).build();
 
     // Queries
 
@@ -457,50 +461,76 @@
 
     @Override
     public void saveSummary(ThreadSummary summary) {
+        try {
+            SUMMARY.insert(summary, storage);
 
-        try {
-            SUMMARY.statementAdd(summary, storage);
-
-        } catch (Exception ignore) { ignore.printStackTrace(); }
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Exception saving summary: " + summary, e);
+        }
     }
 
     @Override
     public List<ThreadSummary> getSummary(VmRef ref, SessionID session, Range<Long> range, int limit) {
+        final List<ThreadSummary> results = new ArrayList<>();
 
-        List<ThreadSummary> result = new ArrayList<>();
+        Query<ThreadSummary> query = SUMMARY.getQuery(SummaryQuery.id);
+
+        QueryValues values = query.createValues();
+        values.set(SummaryQuery.CriteriaId.getVmId, ref.getVmId());
+        values.set(SummaryQuery.CriteriaId.sessionID, session.get());
+        values.set(SummaryQuery.CriteriaId.timeStampGEQ, range.getMin());
+        values.set(SummaryQuery.CriteriaId.timeStampLEQ, range.getMax());
+        values.set(SummaryQuery.CriteriaId.limit, limit);
+
         try {
-            Cursor<ThreadSummary> cursor = SUMMARY.queryGet(ref, session, range, limit, storage);
-            while (cursor.hasNext()) {
-                ThreadSummary summary = cursor.next();
-                result.add(summary);
-            }
-        } catch (Exception ignore) { ignore.printStackTrace(); }
+            SUMMARY.query(values, new ResultHandler<ThreadSummary>() {
+                @Override
+                public void onResult(ThreadSummary result) {
+                    results.add(result);
+                }
+            }, storage);
 
-        return result;
+        } catch (StatementExecutionException e) {
+            e.printStackTrace();
+        }
+
+        return results;
     }
 
     @Override
     public List<ThreadSession> getSessions(VmRef ref, Range<Long> range, int limit) {
-        List<ThreadSession> result = new ArrayList<>();
+        final List<ThreadSession> results = new ArrayList<>();
+
+        Query<ThreadSession> query = SESSIONS.getQuery(SessionQuery.id);
 
-        Cursor<ThreadSession> cursor = null;
+        QueryValues values = query.createValues();
+        values.set(SessionQuery.CriteriaId.getVmId, ref.getVmId());
+        values.set(SessionQuery.CriteriaId.timeStampGEQ, range.getMin());
+        values.set(SessionQuery.CriteriaId.timeStampLEQ, range.getMax());
+        values.set(SessionQuery.CriteriaId.limit, limit);
 
         try {
-            cursor = SESSIONS.queryGet(ref, range, limit, storage);
-            while (cursor.hasNext()) {
-                ThreadSession summary = cursor.next();
-                result.add(summary);
-            }
-        } catch (Exception ignore) { ignore.printStackTrace(); }
+            SESSIONS.query(values, new ResultHandler<ThreadSession>() {
+                @Override
+                public void onResult(ThreadSession result) {
+                    results.add(result);
+                }
+            }, storage);
 
-        return result;
+        } catch (StatementExecutionException e) {
+            e.printStackTrace();
+        }
+
+        return results;
     }
 
     public void saveSession(ThreadSession session) {
         try {
-            SESSIONS.statementAdd(session, storage);
+            SESSIONS.insert(session, storage);
 
-        } catch (Exception ignore) { ignore.printStackTrace(); }
+        } catch (StatementExecutionException e) {
+            logger.log(Level.SEVERE, "Exception saving session: " + session, e);
+        }
     }
 
     @Override
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java	Tue Nov 18 16:03:34 2014 +0100
@@ -60,8 +60,8 @@
         descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS);
 
         // TODO: this needs to go in an helper class
-        descs.addAll(ThreadDaoImpl.SUMMARY.describe());
-        descs.addAll(ThreadDaoImpl.SESSIONS.describe());
+        descs.addAll(ThreadDaoImpl.SUMMARY.describeStatements());
+        descs.addAll(ThreadDaoImpl.SESSIONS.describeStatements());
 
         descs.add(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA);
         descs.add(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS);
@@ -94,7 +94,7 @@
             PreparedParameter[] params) {
         if (descriptor.equals(ThreadDaoImpl.QUERY_THREAD_STATE_PER_THREAD) ||
                 descriptor.equals(ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE)) {
-            // no agent/vm ids in descriptor.
+            // no agent/vm ids in statement.
             return new DescriptorMetadata();
         } else if (descriptor.equals(ThreadDaoImpl.QUERY_LATEST_THREAD_STATE_FOR_THREAD) ||
                 descriptor.equals(ThreadDaoImpl.QUERY_FIRST_THREAD_STATE_FOR_THREAD)) {
@@ -107,7 +107,7 @@
             DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId);
             return metadata;
         } else {
-            throw new IllegalArgumentException("Unknown descriptor ->" + descriptor + "<-");
+            throw new IllegalArgumentException("Unknown statement ->" + descriptor + "<-");
         }
     }
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoKeys.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoKeys.java	Tue Nov 18 16:03:34 2014 +0100
@@ -42,8 +42,19 @@
  *
  */
 public class ThreadDaoKeys {
-    public static final Key<String> SESSION = new Key<>("session");
+
+    public static enum Keys {
 
-    public static final Key<Long> LIVE_THREADS_KEY = new Key<Long>("currentLiveThreads");
-    public static final Key<Long> DAEMON_THREADS_KEY = new Key<Long>("currentDaemonThreads");
+        vmId,
+        agentId,
+        timeStamp,
+        session,
+        currentLiveThreads,
+        currentDaemonThreads,
+
+    }
+
+    public static final Key<String> SESSION = new Key<>(Keys.session.name());
+    public static final Key<Long> LIVE_THREADS_KEY = new Key<Long>(Keys.currentLiveThreads.name());
+    public static final Key<Long> DAEMON_THREADS_KEY = new Key<Long>(Keys.currentDaemonThreads.name());
 }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/Descriptor.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.model.Pojo;
-import java.util.Set;
-
-/**
- *
- */
-public abstract class Descriptor<T extends Pojo> {
-
-    protected Category<T> category;
-    protected void setCategory(Category<T> category) {
-        this.category = category;
-    }
-
-    public Category<T> getCategory() {
-        return category;
-    }
-
-    public abstract Set<String> describe();
-}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/DescriptorBuilder.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.model.Pojo;
-
-/**
- *
- */
-abstract class DescriptorBuilder<T extends Pojo> {
-
-    protected String document;
-    protected Category<T> category;
-
-    DescriptorBuilder(Category<T> category) {
-        this.document = category.getName();
-        this.category = category;
-    }
-
-    public Category<T> getCategory() {
-        return category;
-    }
-
-    abstract public Descriptor<T> build();
-}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptor.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.common.model.Range;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.VmRef;
-import com.redhat.thermostat.thread.model.SessionID;
-import com.redhat.thermostat.thread.model.ThreadSummary;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- *
- */
-public class SummaryDescriptor extends Descriptor<ThreadSummary> {
-
-    private static final Logger logger = LoggingUtils.getLogger(SummaryDescriptor.class);
-
-    protected String rangeDesc;
-    protected String addDesc;
-
-    public Set<String> describe() {
-        Set<String> description = new HashSet<>();
-
-        description.add(rangeDesc);
-        description.add(addDesc);
-
-        return description;
-    }
-
-    public Cursor<ThreadSummary> queryGet(VmRef ref, SessionID session,
-                                                   Range<Long> range, int limit,
-                                                   Storage storage)
-            throws DescriptorParsingException, StatementExecutionException
-    {
-        // "QUERY vm-thread-summary WHERE 'session' = ?s
-        //  AND 'timeStamp' >= ?l
-        //  AND 'timeStamp' <= ?l SORT 'timeStamp' DSC";
-
-        StatementDescriptor<ThreadSummary> desc = null;
-        try {
-            desc = new StatementDescriptor<>(getCategory(), rangeDesc);
-            PreparedStatement<ThreadSummary> prepared =
-                    storage.prepareStatement(desc);
-
-            int i = 0;
-            prepared.setString(i++, session.getId());
-
-            prepared.setLong(i++, range.getMin());
-            prepared.setLong(i++, range.getMax());
-
-            prepared.setInt(i++, limit);
-
-            return prepared.executeQuery();
-
-        } catch (Exception e) {
-            logger.log(Level.WARNING,
-                       "exception executing statement: " + desc, e);
-            throw e;
-        }
-    }
-
-    public void statementAdd(ThreadSummary summary, Storage storage)
-            throws DescriptorParsingException, StatementExecutionException
-    {
-        // "ADD vm-thread-summary SET 'agentId' = ?s , 'vmId' = ?s ,
-        // 'session' = ?s , 'currentLiveThreads' = ?l ,
-        // 'currentDaemonThreads' = ?l , 'timeStamp' = ?l";
-
-        StatementDescriptor<ThreadSummary> desc =
-                new StatementDescriptor<>(getCategory(), addDesc);
-
-        PreparedStatement<ThreadSummary> prepared;
-        try {
-
-            prepared = storage.prepareStatement(desc);
-
-            int i = 0;
-            prepared.setString(i++, summary.getAgentId());
-            prepared.setString(i++, summary.getVmId());
-            prepared.setString(i++, summary.getSession());
-
-            prepared.setLong(i++, summary.getCurrentLiveThreads());
-            prepared.setLong(i++, summary.getCurrentDaemonThreads());
-            prepared.setLong(i++, summary.getTimeStamp());
-
-            prepared.execute();
-
-        } catch (Exception e) {
-            logger.log(Level.WARNING, "exception executing statement: " + desc, e);
-            throw e;
-        }
-    }
-}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorBuilder.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoKeys;
-import com.redhat.thermostat.thread.model.ThreadSummary;
-
-/**
- *
- */
-public class SummaryDescriptorBuilder extends DescriptorBuilder<ThreadSummary> {
-
-    public SummaryDescriptorBuilder() {
-        super(ThreadDaoCategories.THREAD_SUMMARY);
-    }
-
-    @Override
-    public SummaryDescriptor build() {
-
-        SummaryDescriptor descriptor = new SummaryDescriptor();
-        descriptor.setCategory(category);
-
-        StringBuilder summarySinceBuilder = new StringBuilder();
-        summarySinceBuilder.append("QUERY").append(" ");
-        summarySinceBuilder.append(document).append(" ");
-        summarySinceBuilder.append("WHERE").append(" '");
-        summarySinceBuilder.append(ThreadDaoKeys.SESSION.getName()).append("' = ?s AND '");
-        summarySinceBuilder.append(Key.TIMESTAMP.getName()).append("' >= ?l AND '");
-        summarySinceBuilder.append(Key.TIMESTAMP.getName()).append("' <= ?l SORT '");
-        summarySinceBuilder.append(Key.TIMESTAMP.getName()).append("' DSC LIMIT ?i");
-
-        descriptor.rangeDesc = summarySinceBuilder.toString();
-
-        StringBuilder addDesc = new StringBuilder();
-        addDesc.append("ADD").append(" ");
-        addDesc.append(document).append(" ");
-        addDesc.append("SET '");
-        addDesc.append(Key.AGENT_ID.getName()).append("' = ?s , '");
-        addDesc.append(Key.VM_ID.getName()).append("' = ?s , '");
-        addDesc.append(ThreadDaoKeys.SESSION.getName()).append("' = ?s , '");
-        addDesc.append(ThreadDaoKeys.LIVE_THREADS_KEY.getName()).append("' = ?l , '");
-        addDesc.append(ThreadDaoKeys.DAEMON_THREADS_KEY.getName()).append("' = ?l , '");
-        addDesc.append(Key.TIMESTAMP.getName()).append("' = ?l");
-
-        descriptor.addDesc = addDesc.toString();
-
-        return descriptor;
-    }
-}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptor.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.common.model.Range;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.VmRef;
-import com.redhat.thermostat.thread.model.ThreadSession;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- *
- */
-public class ThreadSessionDescriptor extends Descriptor<ThreadSession> {
-
-    private static final Logger logger = LoggingUtils.getLogger(ThreadSessionDescriptor.class);
-
-    protected String querySessions;
-    protected String statementAdd;
-
-    @Override
-    public Set<String> describe() {
-        Set<String> description = new HashSet<>();
-        description.add(querySessions);
-        return description;
-    }
-
-    public Cursor<ThreadSession> queryGet(VmRef ref, Range<Long> range,
-                                          int limit, Storage storage)
-            throws DescriptorParsingException, StatementExecutionException
-    {
-        // "QUERY vm-thread-session WHERE 'vmId' = ?s , 'timeStamp' >= ?l
-        //  AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i";
-
-        StatementDescriptor<ThreadSession> desc = null;
-        try {
-            desc = new StatementDescriptor<>(getCategory(), querySessions);
-            PreparedStatement<ThreadSession> prepared =
-                    storage.prepareStatement(desc);
-
-            int i = 0;
-            prepared.setString(i++, ref.getVmId());
-
-            prepared.setLong(i++, range.getMin());
-            prepared.setLong(i++, range.getMax());
-
-            prepared.setInt(i++, limit);
-
-            return prepared.executeQuery();
-
-        } catch (Exception e) {
-            logger.log(Level.WARNING,
-                       "exception executing statement: " + desc, e);
-            throw e;
-        }
-    }
-
-    public void statementAdd(ThreadSession session, Storage storage)
-            throws DescriptorParsingException, StatementExecutionException
-    {
-        // "ADD vm-thread-session SET 'agentId' = ?s , 'vmId' = ?s ,
-        // 'session' = ?s , 'timeStamp' = ?l"
-
-        StatementDescriptor<ThreadSession> desc =
-                new StatementDescriptor<>(getCategory(), statementAdd);
-
-        PreparedStatement<ThreadSession> prepared;
-        try {
-
-            prepared = storage.prepareStatement(desc);
-
-            int i = 0;
-            prepared.setString(i++, session.getAgentId());
-            prepared.setString(i++, session.getVmId());
-            prepared.setString(i++, session.getSession());
-
-            prepared.setLong(i++, session.getTimeStamp());
-
-            prepared.execute();
-
-        } catch (Exception e) {
-            logger.log(Level.WARNING, "exception executing statement: " + desc, e);
-            throw e;
-        }
-    }
-}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptorBuilder.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoKeys;
-import com.redhat.thermostat.thread.model.ThreadSession;
-
-/**
- *
- */
-public class ThreadSessionDescriptorBuilder extends DescriptorBuilder<ThreadSession> {
-
-    public ThreadSessionDescriptorBuilder() {
-        super(ThreadDaoCategories.THREAD_SESSION);
-    }
-
-    @Override
-    public ThreadSessionDescriptor build() {
-
-        ThreadSessionDescriptor descriptor = new ThreadSessionDescriptor();
-        descriptor.setCategory(category);
-
-        StringBuilder querySessions = new StringBuilder();
-        querySessions.append("QUERY").append(" ");
-        querySessions.append(document).append(" ");
-        querySessions.append("WHERE").append(" '");
-        querySessions.append(Key.VM_ID.getName()).append("' = ?s AND '");
-        querySessions.append(Key.TIMESTAMP.getName()).append("' >= ?l AND '");
-        querySessions.append(Key.TIMESTAMP.getName()).append("' <= ?l SORT '");
-        querySessions.append(Key.TIMESTAMP.getName()).append("' DSC LIMIT ?i");
-
-        descriptor.querySessions = querySessions.toString();
-
-        StringBuilder statementAdd = new StringBuilder();
-        statementAdd.append("ADD").append(" ");
-        statementAdd.append(document).append(" ");
-        statementAdd.append("SET").append(" '");
-        statementAdd.append(Key.AGENT_ID.getName()).append("' = ?s , '");
-        statementAdd.append(Key.VM_ID.getName()).append("' = ?s , '");
-        statementAdd.append(ThreadDaoKeys.SESSION.getName()).append("' = ?s , '");
-        statementAdd.append(Key.TIMESTAMP.getName()).append("' = ?l");
-
-        descriptor.statementAdd = statementAdd.toString();
-
-        return descriptor;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/SessionQuery.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement;
+
+import com.redhat.thermostat.thread.dao.impl.statement.support.FieldDescriptor;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Id;
+import com.redhat.thermostat.thread.dao.impl.statement.support.LimitCriterion;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Query;
+import com.redhat.thermostat.thread.dao.impl.statement.support.SortCriterion;
+import com.redhat.thermostat.thread.dao.impl.statement.support.StatementUtils;
+import com.redhat.thermostat.thread.dao.impl.statement.support.TypeMapper;
+import com.redhat.thermostat.thread.dao.impl.statement.support.WhereCriterion;
+import com.redhat.thermostat.thread.model.ThreadSession;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class SessionQuery extends Query<ThreadSession> {
+
+    public static final Id id = new Id(ThreadSession.class.getSimpleName());
+
+    public static class CriteriaId {
+        public static final Id getVmId = new Id("0");
+        public static final Id timeStampGEQ = new Id("1");
+        public static final Id timeStampLEQ = new Id("2");
+        public static final Id limit = new Id("3");
+
+    }
+
+    @Override
+    public Id getId() {
+        return id;
+    }
+
+    @Override
+    protected void describe(Criteria criteria) {
+        List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadSession.class);
+        final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors);
+
+        criteria.add(new WhereCriterion(CriteriaId.getVmId, map.get("vmId"),
+                                        TypeMapper.Criteria.Equal));
+        criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"),
+                                        TypeMapper.Criteria.GreaterEqual));
+        criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"),
+                                        TypeMapper.Criteria.LessEqual));
+
+        criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending));
+        criteria.add(new LimitCriterion(CriteriaId.limit));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/SummaryQuery.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement;
+
+import com.redhat.thermostat.thread.dao.impl.statement.support.FieldDescriptor;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Id;
+import com.redhat.thermostat.thread.dao.impl.statement.support.LimitCriterion;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Query;
+import com.redhat.thermostat.thread.dao.impl.statement.support.SortCriterion;
+import com.redhat.thermostat.thread.dao.impl.statement.support.StatementUtils;
+import com.redhat.thermostat.thread.dao.impl.statement.support.TypeMapper;
+import com.redhat.thermostat.thread.dao.impl.statement.support.WhereCriterion;
+import com.redhat.thermostat.thread.model.ThreadSession;
+import com.redhat.thermostat.thread.model.ThreadSummary;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class SummaryQuery extends Query<ThreadSummary> {
+
+    public static final Id id = new Id(SummaryQuery.class.getSimpleName());
+
+    public static class CriteriaId {
+        public static final Id getVmId = new Id("0");
+        public static final Id timeStampGEQ = new Id("1");
+        public static final Id timeStampLEQ = new Id("2");
+        public static final Id sessionID = new Id("3");
+        public static final Id limit = new Id("4");
+
+    }
+
+    @Override
+    public Id getId() {
+        return id;
+    }
+
+    @Override
+    protected void describe(Criteria criteria) {
+        List<FieldDescriptor> descriptors = StatementUtils.createDescriptors
+                (ThreadSession.class);
+        final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors);
+
+        criteria.add(new WhereCriterion(CriteriaId.getVmId, map.get("vmId"),
+                                        TypeMapper.Criteria.Equal));
+        criteria.add(new WhereCriterion(CriteriaId.sessionID, map.get("session"),
+                                        TypeMapper.Criteria.Equal));
+        criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"),
+                                        TypeMapper.Criteria.GreaterEqual));
+        criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"),
+                                        TypeMapper.Criteria.LessEqual));
+
+        criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending));
+
+        criteria.add(new LimitCriterion(CriteriaId.limit));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapter.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.Pojo;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ */
+public class BeanAdapter<T extends Pojo> {
+    public static final Id INSERT = new Id("BeanAdapter_Insert");
+
+    private static final Logger logger = LoggingUtils.getLogger(BeanAdapter.class);
+
+    protected Category<T> category;
+
+    private Map<Id, Statement> describedQueries;
+    private Map<Id, Query<T>> queries;
+    private List<FieldDescriptor> fieldDescriptors;
+
+    public BeanAdapter() {
+        this.queries = new HashMap<>();
+        this.describedQueries = new HashMap<>();
+    }
+
+    protected void setCategory(Category<T> category) {
+        this.category = category;
+    }
+
+    public Category<T> getCategory() {
+        return category;
+    }
+
+    public Set<String> describeStatements() {
+        Set<String> descriptions = new HashSet<>();
+        for (Statement statement : describedQueries.values()) {
+            descriptions.add(statement.get());
+        }
+        return descriptions;
+    }
+
+    public void insert(T bean, Storage storage)
+            throws StatementExecutionException
+    {
+        Statement statement = describedQueries.get(INSERT);
+
+        StatementDescriptor<T> desc =
+                new StatementDescriptor<>(category, statement.get());
+        try {
+            PreparedStatement<T> prepared = storage.prepareStatement(desc);
+            int i = 0;
+            for (FieldDescriptor descriptor : fieldDescriptors) {
+                Value value = StatementUtils.getValue(bean, descriptor);
+                StatementUtils.setData(prepared, value, i++);
+            }
+
+            prepared.execute();
+
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
+        }
+    }
+
+    public Query<T> getQuery(Id id) {
+        return queries.get(id);
+    }
+
+    public void query(QueryValues values, ResultHandler<T> handler,
+                      Storage storage) throws StatementExecutionException
+    {
+        Objects.requireNonNull(handler, "ResultHandler cannot be null");
+        Objects.requireNonNull(values, "QueryValues cannot be null");
+        Objects.requireNonNull(storage, "Storage cannot be null");
+
+        Query query = values.getQuery();
+        if (!queries.containsKey(query.getId())) {
+            throw new IllegalArgumentException("This adapter does not know" +
+                                               "about the given query: " +
+                                               query.getId());
+        }
+
+        Statement statement = describedQueries.get(query.getId());
+        List<Criterion> criteria = query.describe();
+
+        StatementDescriptor<T> desc =
+                new StatementDescriptor<>(category, statement.get());
+        PreparedStatement<T> prepared = null;
+        try {
+            prepared = storage.prepareStatement(desc);
+            int i = 0;
+            for (Criterion criterion : criteria) {
+                // sort doesn't take values
+                if (criterion instanceof SortCriterion) {
+                    continue;
+                }
+
+                Value value = values.getValue(criterion);
+                StatementUtils.setData(prepared, value, i++);
+            }
+
+        } catch (DescriptorParsingException e) {
+            logger.log(Level.SEVERE, "Preparing stmt '" + desc +
+                                     "' failed!", e);
+
+            // this can't really happen, but if it does is serious
+            throw new AssertionError("Autogenerated statement failed to parse",
+                                     e);
+        }
+
+        Cursor<T> cursor = prepared.executeQuery();
+        while (cursor.hasNext()) {
+            T result = cursor.next();
+            try {
+                handler.onResult(result);
+
+            } catch (Throwable t) {
+                logger.log(Level.SEVERE, "Exception executing results", t);
+            }
+        }
+    }
+
+    protected void addStatement(Id id, Statement statement) {
+        describedQueries.put(id, statement);
+    }
+
+    protected void addQuery(Id id, Query query) {
+        queries.put(id, query);
+    }
+
+    protected void setFieldDescriptors(List<FieldDescriptor> fieldDescriptors) {
+        this.fieldDescriptors = fieldDescriptors;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapterBuilder.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.model.Pojo;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class BeanAdapterBuilder<T extends Pojo> {
+
+    private Class<T> target;
+    private BeanAdapter<T> adapter;
+
+    private List<Query<T>> queries;
+
+    public BeanAdapterBuilder(Class<T> target, List<Query<T>> queries) {
+        this.target = target;
+        this.queries = queries;
+    }
+
+    public BeanAdapterBuilder(Class<T> target, Query<T> query) {
+        this(target, new ArrayList<Query<T>>());
+        queries.add(query);
+    }
+
+    public BeanAdapter<T> build() {
+        try {
+            Category<T> category = new CategoryBuilder<>(target).build();
+            List<FieldDescriptor> fieldDescriptors =
+                    StatementUtils.createDescriptors(target);
+
+            adapter = new BeanAdapter<>();
+            adapter.setCategory(category);
+            adapter.setFieldDescriptors(fieldDescriptors);
+
+            createInsert(fieldDescriptors);
+            createQueries();
+
+            return adapter;
+
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    protected void createQueries() {
+        for (Query<T> query : queries) {
+            createQuery(query);
+        }
+    }
+
+    private void createQuery(Query<T> query) {
+        List<Criterion> queryDescriptors = query.describe();
+
+        QueryEngine engine = new QueryEngine();
+        engine.prologue(adapter.getCategory());
+        for (Criterion criterion : queryDescriptors) {
+            if (criterion instanceof WhereCriterion) {
+                WhereCriterion where = (WhereCriterion) criterion;
+                engine.add(where.getFieldDescriptor(), where.getCriteria());
+
+            } else if (criterion instanceof SortCriterion) {
+                SortCriterion sort = (SortCriterion) criterion;
+                engine.sort(sort.getFieldDescriptor(), sort.getCriteria());
+
+            } else if (criterion instanceof LimitCriterion) {
+                engine.limit();
+            }
+        }
+
+        adapter.addStatement(query.getId(), engine.build());
+        adapter.addQuery(query.getId(), query);
+    }
+
+    protected void createInsert(List<FieldDescriptor> descriptors) {
+
+        InsertEngine engine = new InsertEngine();
+        engine.prologue(adapter.getCategory());
+
+        for (FieldDescriptor descriptor : descriptors) {
+            engine.add(descriptor);
+        }
+
+        adapter.addStatement(BeanAdapter.INSERT, engine.build());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Category.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Category {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/CategoryBuilder.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.model.Pojo;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class CategoryBuilder<T extends Pojo> {
+
+    private static final String LOCK = new String("CategoryBuilder_lock");
+    private static final Map<String, Category> categories = new HashMap<>();
+
+    private Class<T> bean;
+
+    public CategoryBuilder(Class<T> bean) {
+        this.bean = bean;
+    }
+
+    public Category<T> build() {
+
+        synchronized (LOCK) {
+
+            String document = StatementUtils.getDocument(bean);
+
+            // This helps performance as well, but it's needed because Category
+            // doesn't allow us to create the same twice, even with all the
+            // same data; categories are in fact some kind of singleton
+            if (categories.containsKey(document)) {
+                return categories.get(document);
+            }
+
+            List<FieldDescriptor> descriptors =
+                    StatementUtils.createDescriptors(bean);
+
+            // we first build the keys and the indexed keys
+            List<Key> indexed = new ArrayList<>();
+            List<Key> keys = new ArrayList<>();
+
+            // key are easy, the arguments are in the form:
+            // new Key<Type>(String name), we don't need reflection
+
+            for (FieldDescriptor descriptor : descriptors) {
+
+                Key key = new Key(descriptor.getName());
+
+                keys.add(key);
+                if (descriptor.isIndexed()) {
+                    indexed.add(key);
+                }
+            }
+
+            List<Class> argumentClasses = new ArrayList<>();
+            argumentClasses.add(String.class);
+            argumentClasses.add(Class.class);
+            argumentClasses.add(List.class);
+
+            List argumentObjects = new ArrayList();
+            argumentObjects.add(document);
+            argumentObjects.add(bean);
+            argumentObjects.add(keys);
+
+            // indexed keys are optional
+            if (!indexed.isEmpty()) {
+                argumentClasses.add(List.class);
+                argumentObjects.add(indexed);
+            }
+
+            Class[] classes = argumentClasses.toArray(new Class[argumentClasses.size()]);
+            Object[] objects = argumentObjects.toArray();
+
+            Category<T> category = create(classes, objects);
+            categories.put(document, category);
+
+            return category;
+        }
+    }
+
+    private Category<T> create(Class[] classes, Object[] objects) {
+
+        // we are using this constructor:
+        // Category(String name, Class<T> dataClass,
+        //          List<Key<?>> keys, List<Key<?>> indexedKeys)
+
+        try {
+            Constructor<Category> constructor =
+                    Category.class.getConstructor(classes);
+            constructor.setAccessible(true);
+
+            return constructor.newInstance(objects);
+
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Criterion.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+public interface Criterion {
+    Id getId();
+    Class<?> getType();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/FieldDescriptor.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.util.Objects;
+
+/**
+ *
+ */
+public class FieldDescriptor {
+    private Class<?> type;
+    private String name;
+    private boolean indexed;
+
+    public void setType(Class<?> type) {
+        this.type = type;
+    }
+
+    public Class<?> getType() {
+        return type;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setIndexed(boolean indexed) {
+        this.indexed = indexed;
+    }
+
+    public boolean isIndexed() {
+        return indexed;
+    }
+
+    @Override
+    public String toString() {
+        return "[FieldDescriptor: " +
+                "type = " + type +
+                ", name = '" + name + '\'' +
+                ", indexed = " + indexed +
+                ']';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        FieldDescriptor that = (FieldDescriptor) o;
+        return Objects.equals(name, that.name);
+    }
+
+    @Override
+    public int hashCode() {
+        return name != null ? name.hashCode() : 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Id.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.util.UUID;
+
+/**
+ *
+ */
+public class Id {
+    private String id;
+
+    public Id() {
+        id = UUID.randomUUID().toString();
+    }
+
+    public Id(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Id sessionID = (Id) o;
+
+        if (id != null ? !id.equals(sessionID.id) : sessionID.id != null)
+            return false;
+
+        return true;
+    }
+
+    public String get() {
+        return id;
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Indexed.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Indexed {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/InsertEngine.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+class InsertEngine extends StatementEngine {
+
+    public InsertEngine() {
+        super(TypeMapper.Statement.Insert);
+        delimiter = TypeMapper.Symbol.InsertSeparator.id();
+        tokens.add(TypeMapper.Clause.Add.id());
+    }
+
+    public InsertEngine add(FieldDescriptor descriptor) {
+        super.add(descriptor, TypeMapper.Criteria.Equal);
+        return this;
+    }
+
+    @Override
+    protected void addPrologueClause() {
+        tokens.add(TypeMapper.Clause.Set.id());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/LimitCriterion.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+public class LimitCriterion implements Criterion {
+
+    private Id id;
+
+    public LimitCriterion(Id id) {
+        this.id = id;
+    }
+
+    @Override
+    public Id getId() {
+        return id;
+    }
+
+    @Override
+    public Class<?> getType() {
+        return int.class;
+    }
+
+    @Override
+    public String toString() {
+        return "Limit";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Query.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.model.Pojo;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public abstract class Query<T extends Pojo> {
+
+    protected final class Criteria {
+        private List<Criterion> criteria;
+        private Map<Id, Criterion> map;
+
+        Criteria() {
+            criteria = new ArrayList<>();
+            map = new HashMap<>();
+        }
+
+        public void add(Criterion criterion) {
+            Id id = criterion.getId();
+            if (map.containsKey(id)) {
+                throw new IllegalArgumentException("Already contains criteria" +
+                                                   " with this id." +
+                                                   " New: " + criterion +
+                                                   " Old: " + map.get(id));
+            }
+            map.put(id, criterion);
+            criteria.add(criterion);
+        }
+    }
+
+    private List<Criterion> describedQuery;
+    private Criteria criteria;
+
+    public Query() {
+        criteria = new Criteria();
+    }
+
+    public abstract Id getId();
+
+    public final List<Criterion> describe() {
+        if (describedQuery == null) {
+            describe(criteria);
+            describedQuery = Collections.unmodifiableList(criteria.criteria);
+        }
+        return describedQuery;
+    }
+
+    protected abstract void describe(Criteria criteria);
+
+    public final QueryValues createValues() {
+        if (describedQuery == null) {
+            throw new IllegalStateException("Query must be described first");
+        }
+
+        QueryValues setter = new QueryValues(this);
+        setter.addCriteria(describedQuery);
+
+        return setter;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryEngine.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import static com.redhat.thermostat.thread.dao.impl.statement.support.TypeMapper.Symbol.Quote;
+import static com.redhat.thermostat.thread.dao.impl.statement.support.TypeMapper.Symbol.Space;
+
+/**
+ *
+ */
+class QueryEngine extends StatementEngine {
+
+    private String limit;
+    private String sort;
+
+    public QueryEngine() {
+        super(TypeMapper.Statement.Query);
+        addDelimiter = false;
+        delimiter = TypeMapper.Symbol.InsertSeparator.id();
+        delimiter = TypeMapper.Symbol.QuerySeparator.id();
+        tokens.add(TypeMapper.Clause.Query.id());
+    }
+
+    public QueryEngine add(FieldDescriptor descriptor, TypeMapper.Criteria criteria) {
+
+        if (addDelimiter) {
+            tokens.add(delimiter);
+        }
+
+        addDelimiter = true;
+
+        StringBuilder field = new StringBuilder();
+
+        field.append(Quote.id());
+        field.append(descriptor.getName());
+        field.append(Quote.id());
+
+        tokens.add(field.toString());
+
+        tokens.add(criteria.id());
+        tokens.add(TypeMapper.get(descriptor.getType()));
+
+        return this;
+    }
+
+    public QueryEngine sort(FieldDescriptor descriptor, TypeMapper.Sort criteria) {
+
+        StringBuilder field = new StringBuilder();
+
+        field.append(TypeMapper.Symbol.Sort.id());
+        field.append(Space.id());
+
+        field.append(Quote.id());
+        field.append(descriptor.getName());
+        field.append(Quote.id());
+
+        field.append(Space.id());
+        field.append(criteria.id());
+
+        sort = field.toString();
+
+        return this;
+    }
+
+    public QueryEngine limit() {
+
+        StringBuilder field = new StringBuilder();
+
+        field.append(TypeMapper.Symbol.Limit.id());
+        field.append(Space.id());
+        field.append(TypeMapper.get(int.class));
+
+        limit = field.toString();
+
+        return this;
+    }
+
+    @Override
+    protected void addPrologueClause() {
+        tokens.add(TypeMapper.Clause.Where.id());
+    }
+
+    @Override
+    protected void buildImpl(StringBuilder builder) {
+        if (sort != null) {
+            builder.append(Space.id()).append(sort);
+        }
+
+        if (limit != null) {
+            builder.append(Space.id()).append(limit);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryValues.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class QueryValues {
+
+    private static final Class EMPTY_VALUE = QueryValues.class;
+
+    private Query query;
+    private Map<Id, Value> values;
+    private Map<Id, Class> types;
+
+    protected QueryValues(Query query) {
+        this.query = query;
+        values = new HashMap<>();
+        types = new HashMap<>();
+    }
+
+    public Query getQuery() {
+        return query;
+    }
+
+    public void set(Id criteriaId, String value) {
+        setImpl(criteriaId, value);
+    }
+
+    public void set(Id criteriaId, long value) {
+        setImpl(criteriaId, value);
+    }
+
+    public void set(Id criteriaId, int value) {
+        setImpl(criteriaId, value);
+    }
+
+    public void set(Id criteriaId, boolean value) {
+        setImpl(criteriaId, value);
+    }
+
+    private void setImpl(Id criteriaId, Object value) {
+        if (!values.containsKey(criteriaId)) {
+            throw new IllegalArgumentException("Query does not contain this criteria");
+        }
+        check(criteriaId, value);
+    }
+
+    private void check(Id criteriaId, Object value) {
+
+        Class type = value.getClass();
+        Class targetType = types.get(criteriaId);
+
+        boolean match = false;
+        if (targetType.isAssignableFrom(int.class) ||
+            targetType.isAssignableFrom(Integer.class))
+        {
+            if (type.isAssignableFrom(int.class) ||
+                type.isAssignableFrom(Integer.class))
+            {
+                match = true;
+            }
+        } else if (targetType.isAssignableFrom(long.class) ||
+                   targetType.isAssignableFrom(Long.class))
+        {
+            if (type.isAssignableFrom(long.class) ||
+                type.isAssignableFrom(Long.class))
+            {
+                match = true;
+            }
+        } else if (targetType.isAssignableFrom(boolean.class) ||
+                   targetType.isAssignableFrom(Boolean.class))
+        {
+            if (type.isAssignableFrom(boolean.class) ||
+                type.isAssignableFrom(Boolean.class))
+            {
+                match = true;
+            }
+        } else if (targetType.isAssignableFrom(String.class)) {
+            if (type.isAssignableFrom(String.class))
+            {
+                match = true;
+            }
+        }
+
+        if (!match) {
+            throw new IllegalArgumentException("value type does not match " +
+                                               "target criteria with id: " +
+                                               criteriaId.get() +
+                                               " Wanted: "  +
+                                               targetType + ", received: "  +
+                                               type);
+        }
+
+        values.put(criteriaId, new Value(value));
+    }
+
+    public void set(Criterion criterion, Object value) {
+        setImpl(criterion.getId(), value);
+    }
+
+    Value getValue(Criterion criterion) {
+        return values.get(criterion.getId());
+    }
+
+    void addCriteria(List<Criterion> _criteria) {
+        for (Criterion criterion : _criteria) {
+
+            // sort doesn't take values
+            if (criterion instanceof SortCriterion) {
+                continue;
+            }
+
+            Id id = criterion.getId();
+            values.put(id, new Value(EMPTY_VALUE));
+            types.put(id, criterion.getType());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/ResultHandler.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+public interface ResultHandler<T> {
+    void onResult(T result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/SortCriterion.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+public class SortCriterion implements Criterion {
+    private FieldDescriptor descriptor;
+    private TypeMapper.Sort criteria;
+
+    private Id id;
+
+    public SortCriterion(FieldDescriptor descriptor,
+                         TypeMapper.Sort criteria)
+    {
+        this(new Id(descriptor.getName() + ":" + criteria.name()), descriptor, criteria);
+    }
+
+    private SortCriterion(Id id,
+                          FieldDescriptor descriptor,
+                          TypeMapper.Sort criteria)
+    {
+        this.descriptor = descriptor;
+        this.criteria = criteria;
+    }
+
+    @Override
+    public Class<?> getType() {
+        return descriptor.getType();
+    }
+
+    public FieldDescriptor getFieldDescriptor() {
+        return descriptor;
+    }
+
+    public TypeMapper.Sort getCriteria() {
+        return criteria;
+    }
+
+    @Override
+    public Id getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return "[Sort: " + criteria.name() + " -: " + descriptor + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Statement.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+class Statement {
+    private String statement;
+
+    public Statement(String statement) {
+        this.statement = statement;
+    }
+
+    public String get() {
+        return statement;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null) {
+            return false;
+        }
+
+        if (o instanceof String && statement != null) {
+            return o.equals(statement);
+        }
+
+        if (getClass() != o.getClass()) return false;
+
+        Statement statement1 = (Statement) o;
+
+        if (statement != null ? !statement.equals(statement1.statement) :
+                                 statement1.statement != null)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return statement != null ? statement.hashCode() : 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementEngine.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.model.Pojo;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.redhat.thermostat.thread.dao.impl.statement.support.TypeMapper.Symbol.Quote;
+import static com.redhat.thermostat.thread.dao.impl.statement.support.TypeMapper.Symbol.Space;
+
+/**
+ *
+ */
+abstract class StatementEngine {
+
+    protected List<String> tokens;
+
+    private TypeMapper.Statement type;
+    protected String delimiter;
+
+    protected boolean addDelimiter;
+
+    protected StatementEngine(TypeMapper.Statement type) {
+        tokens = new LinkedList<>();
+        this.type = type;
+        addDelimiter = false;
+    }
+
+    protected StatementEngine add(FieldDescriptor descriptor, TypeMapper.Criteria criteria) {
+
+        if (addDelimiter) {
+            tokens.add(delimiter);
+        }
+
+        addDelimiter = true;
+
+        StringBuilder field = new StringBuilder();
+
+        field.append(Quote.id());
+        field.append(descriptor.getName());
+        field.append(Quote.id());
+
+        tokens.add(field.toString());
+
+        tokens.add(criteria.id());
+        tokens.add(TypeMapper.get(descriptor.getType()));
+
+        return this;
+    }
+
+    protected abstract void addPrologueClause();
+
+    public StatementEngine prologue(com.redhat.thermostat.storage.core.Category<? extends Pojo> category) {
+        tokens.add(category.getName());
+        addPrologueClause();
+        return this;
+    }
+
+    protected void buildImpl(StringBuilder builder) {}
+
+
+    public Statement build() {
+        StringBuilder builder = new StringBuilder();
+        for (String token : tokens) {
+            builder.append(token).append(Space.id());
+        }
+        int position = builder.length() - 1;
+        builder.deleteCharAt(position);
+
+        buildImpl(builder);
+
+        return new Statement(builder.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementUtils.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.model.Pojo;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class StatementUtils {
+
+    static boolean isPersistent(PropertyDescriptor desc) {
+        return hasAnnotation(desc, Persist.class);
+    }
+
+    static boolean isIndexed(PropertyDescriptor desc) {
+        return hasAnnotation(desc, Indexed.class);
+    }
+
+    static <T extends Pojo> String getDocument(Class<T> pojoClass) {
+        if (!pojoClass.isAnnotationPresent(Category.class)) {
+            return null;
+        }
+
+        return pojoClass.getAnnotation(Category.class).value();
+    }
+
+    static boolean hasAnnotation(PropertyDescriptor desc,
+                                 Class<? extends Annotation> annotation)
+    {
+        Method readMethod = desc.getReadMethod();
+        boolean hasRead = (readMethod != null &&
+                           readMethod.isAnnotationPresent(annotation));
+
+        Method writeMethod = desc.getWriteMethod();
+        boolean hasWrite = (writeMethod != null &&
+                            writeMethod.isAnnotationPresent(annotation));
+
+        return hasRead && hasWrite;
+    }
+
+    public static Map<String, FieldDescriptor> createDescriptorMap(List<FieldDescriptor> descriptors) {
+        Map<String, FieldDescriptor> map = new HashMap<>();
+        for (FieldDescriptor desc : descriptors) {
+            map.put(desc.getName(), desc);
+        }
+        return map;
+    }
+
+    public static <T extends Pojo> List<FieldDescriptor> createDescriptors(Class<T> pojoClass) {
+        try {
+            BeanInfo info = Introspector.getBeanInfo(pojoClass);
+            PropertyDescriptor[] props = info.getPropertyDescriptors();
+
+            List<FieldDescriptor> descriptors = new ArrayList<>();
+            for (PropertyDescriptor desc : props) {
+
+                if (StatementUtils.isPersistent(desc)) {
+                    FieldDescriptor descriptor = new FieldDescriptor();
+                    descriptor.setType(desc.getPropertyType());
+                    descriptor.setName(desc.getName());
+                    descriptor.setIndexed(StatementUtils.isIndexed(desc));
+
+                    descriptors.add(descriptor);
+                }
+            }
+
+            // Afaik it's not specified that methods are returned or listed in
+            // any particular order by Introspector.getBeanInfo, so if we don't
+            // sort, we may end up with two differently ordered lists in two
+            // different calls to this method.
+            // This is a problem because the prepated statement API doesn't
+            // check if two statements are the same if fields are sorted in
+            // random order, it only considers two statements the same if
+            // their string representation completely matches;
+            // it also make the code depending on FieldDescriptor easier to
+            // write if it can count on the ordering being always consistent
+            Collections.sort(descriptors, new Comparator<FieldDescriptor>() {
+                @Override
+                public int compare(FieldDescriptor o1, FieldDescriptor o2) {
+                    return o1.getName().compareTo(o2.getName());
+                }
+            });
+
+            return Collections.unmodifiableList(descriptors);
+
+        } catch (IntrospectionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static <T extends Pojo> Value getValue(T bean,  FieldDescriptor descriptor)
+    {
+        try {
+            PropertyDescriptor property =
+                    new PropertyDescriptor(descriptor.getName(),
+                                           bean.getClass());
+            Method method = property.getReadMethod();
+            method.setAccessible(true);
+
+            return new Value(method.invoke(bean, new Object[0]));
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static <T extends Pojo> void setData(PreparedStatement<T> prepared,
+                                         Value value, int index)
+    {
+        Class type = value.get().getClass();
+        if (type.isAssignableFrom(int.class) ||
+            type.isAssignableFrom(Integer.class))
+        {
+            prepared.setInt(index, ((Integer) value.get()).intValue());
+
+        } else if (type.isAssignableFrom(long.class) ||
+                   type.isAssignableFrom(Long.class))
+        {
+            prepared.setLong(index, ((Long) value.get()).longValue());
+
+        } else if (type.isAssignableFrom(boolean.class) ||
+                   type.isAssignableFrom(Boolean.class))
+        {
+            prepared.setBoolean(index, ((Boolean) value.get()).booleanValue());
+
+        } else if (type.isAssignableFrom(String.class)) {
+            prepared.setString(index, (String) value.get());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/TypeMapper.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class TypeMapper {
+
+    private static final Map<Class, String> map = new HashMap<>();
+    static {
+        map.put(String.class, "?s");
+        map.put(int.class, "?i");
+        map.put(long.class, "?l");
+        map.put(boolean.class, "?b");
+    }
+
+    static String get(Class type) {
+        return map.get(type);
+    }
+
+    static enum Symbol {
+
+        QuerySeparator("AND"),
+        InsertSeparator(","),
+
+        Quote("'"),
+        Space(" "),
+
+        Sort("SORT"),
+        Limit("LIMIT"),
+
+        ;
+
+        private final String definition;
+        Symbol(String definition) {
+            this.definition = definition;
+        }
+
+        public String id() {
+            return definition;
+        }
+    }
+
+    public static enum Criteria {
+        Less("<"),
+        LessEqual("<="),
+
+        Equal("="),
+
+        Greater(">"),
+        GreaterEqual(">="),
+
+        ;
+
+        private final String definition;
+        Criteria(String definition) {
+            this.definition = definition;
+        }
+
+        public String id() {
+            return definition;
+        }
+    }
+
+    public static enum Sort {
+        Ascending("ASC"),
+        Descending("DSC"),
+        ;
+
+        private final String definition;
+        Sort(String definition) {
+            this.definition = definition;
+        }
+
+        public String id() {
+            return definition;
+        }
+    }
+
+    static enum Statement {
+        Query,
+        Insert,
+    }
+
+    static enum Clause {
+
+        Add("ADD"),
+        Set("SET"),
+
+        Query("QUERY"),
+        Where("WHERE"),
+
+        ;
+
+        private final String definition;
+        Clause(String definition) {
+            this.definition = definition;
+        }
+
+        public String id() {
+            return definition;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/Value.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+public class Value {
+    private Object value;
+
+    public Value(Object value) {
+        this.value = value;
+    }
+
+    public Object get() {
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/support/WhereCriterion.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+/**
+ *
+ */
+public class WhereCriterion implements Criterion {
+
+    private Id id;
+
+    private FieldDescriptor descriptor;
+    private TypeMapper.Criteria criteria;
+
+    public WhereCriterion(Id id,
+                          FieldDescriptor descriptor,
+                          TypeMapper.Criteria criteria)
+    {
+        this.descriptor = descriptor;
+        this.criteria = criteria;
+        this.id = id;
+    }
+
+    @Override
+    public Class<?> getType() {
+        return descriptor.getType();
+    }
+
+    @Override
+    public Id getId() {
+        return id;
+    }
+
+    public FieldDescriptor getFieldDescriptor() {
+        return descriptor;
+    }
+
+    public TypeMapper.Criteria getCriteria() {
+        return criteria;
+    }
+
+    @Override
+    public String toString() {
+        return "[" + criteria.name() + " -: " + descriptor + "]";
+    }
+}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/SessionID.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/SessionID.java	Tue Nov 18 16:03:34 2014 +0100
@@ -36,42 +36,17 @@
 
 package com.redhat.thermostat.thread.model;
 
-import java.util.UUID;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Id;
 
 /**
  *
  */
-public class SessionID  {
-
-    private String id;
-
+public class SessionID extends Id {
     public SessionID() {
-        id = UUID.randomUUID().toString();
+        super();
     }
 
     public SessionID(String id) {
-        this.id = id;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        SessionID sessionID = (SessionID) o;
-
-        if (id != null ? !id.equals(sessionID.id) : sessionID.id != null)
-            return false;
-
-        return true;
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    @Override
-    public int hashCode() {
-        return id != null ? id.hashCode() : 0;
+        super(id);
     }
 }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSession.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSession.java	Tue Nov 18 16:03:34 2014 +0100
@@ -40,10 +40,14 @@
 import com.redhat.thermostat.storage.core.Persist;
 import com.redhat.thermostat.storage.model.BasePojo;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Category;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Indexed;
 
 /**
  *
  */
+@Category(ThreadDaoCategories.Categories.SESSION)
 @Entity
 public class ThreadSession extends BasePojo implements TimeStampedPojo {
 
@@ -60,11 +64,13 @@
         super(writerId);
     }
 
+    @Indexed
     @Persist
     public void setVmId(String vmId) {
         this.vmId = vmId;
     }
 
+    @Indexed
     @Persist
     public String getVmId() {
         return vmId;
@@ -86,12 +92,14 @@
                ", vm: " + vmId + "]";
     }
 
+    @Indexed
     @Persist
     public void setSession(String session) {
         this.session = session;
         sessionID = new SessionID(session);
     }
 
+    @Indexed
     @Persist
     public String getSession() {
         return session;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Tue Nov 18 16:03:34 2014 +0100
@@ -40,8 +40,11 @@
 import com.redhat.thermostat.storage.core.Persist;
 import com.redhat.thermostat.storage.model.BasePojo;
 import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Category;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Indexed;
 
-
+@Category(ThreadDaoCategories.Categories.SUMMARY)
 @Entity
 public class ThreadSummary extends BasePojo implements TimeStampedPojo {
 
@@ -92,11 +95,13 @@
         this.daemonThreads = daemonThreads;
     }
 
+    @Indexed
     @Persist
     public long getTimeStamp() {
         return timestamp;
     }
 
+    @Indexed
     @Persist
     public void setTimeStamp(long timestamp) {
         this.timestamp = timestamp;
@@ -108,12 +113,14 @@
                currentLiveThreads + ", daemonThreads: " + daemonThreads + "]";
     }
 
+    @Indexed
     @Persist
     public void setSession(String session) {
         this.session = session;
         sessionID = new SessionID(session);
     }
 
+    @Indexed
     @Persist
     public String getSession() {
         return session;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementBeanAdapterRegistrationTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl;
+
+import com.redhat.thermostat.storage.core.PreparedParameter;
+import com.redhat.thermostat.storage.core.auth.DescriptorMetadata;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ThreadDAOImplStatementBeanAdapterRegistrationTest {
+
+    static class Triple<S, T, U> {
+        final S first;
+        final T second;
+        final U third;
+
+        public Triple(S first, T second, U third) {
+            this.first = first;
+            this.second = second;
+            this.third = third;
+        }
+    }
+    
+    @Test
+    public void registersAllDescriptors() {
+        ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(20, descriptors.size());
+        assertFalse("null statement not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(ThreadDaoImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, ThreadDaoImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration threadDaoReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(ThreadDaoImplStatementDescriptorRegistration.class.getName())) {
+                threadDaoReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(threadDaoReg);
+        assertEquals(20, threadDaoReg.getStatementDescriptors().size());
+    }
+    
+    private Triple<String, String, PreparedParameter[]> setupForMetaDataTest() {
+        PreparedParameter agentIdParam = mock(PreparedParameter.class);
+        PreparedParameter vmIdParam = mock(PreparedParameter.class);
+        String agentId = "agentId";
+        String vmId = "vmId";
+        when(agentIdParam.getValue()).thenReturn(agentId);
+        when(vmIdParam.getValue()).thenReturn(vmId);
+        PreparedParameter[] params = new PreparedParameter[] { agentIdParam,
+                vmIdParam };
+        return new Triple<String, String, PreparedParameter[]>(agentId, vmId,
+                params);
+    }
+
+    private void assertThreadMetadata(
+            Triple<String, String, PreparedParameter[]> triple,
+            DescriptorMetadata data) {
+        assertNotNull(data);
+        assertEquals(triple.first, data.getAgentId());
+        assertEquals(triple.second, data.getVmId());
+    }
+    
+    @Test
+    public void canGetMetadataForLatestDeadlockQuery() {
+        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest(); 
+        
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO, triple.third);
+        assertThreadMetadata(triple, data);
+    }
+
+    @Test
+    public void canGetMetadataForLatestHarvestingStatusQuery() {
+        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest(); 
+        
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS, triple.third);
+        assertThreadMetadata(triple, data);
+    }
+
+    @Test
+    public void canGetMetadataForThreadHeader() {
+        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
+
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_THREAD_HEADER, triple.third);
+        assertThreadMetadata(triple, data);
+    }
+
+    @Test
+    public void canGetMetadataAllThreadHeaders() {
+        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
+
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_ALL_THREAD_HEADERS, triple.third);
+        assertThreadMetadata(triple, data);
+    }
+
+    @Test
+    public void canGetMetadataLastThreadStateForThread() {
+        PreparedParameter str1 = new PreparedParameter();
+        str1.setType(String.class);
+        str1.setValue("foo-agent");
+        PreparedParameter str2 = new PreparedParameter();
+        str2.setType(String.class);
+        str2.setValue("something");
+        PreparedParameter[] params = new PreparedParameter[] {
+                str1, str2
+        };
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_THREAD_STATE_FOR_THREAD, params);
+        assertNotNull(data);
+        assertEquals("foo-agent", data.getAgentId());
+        assertFalse(data.hasVmId());
+        assertTrue(data.hasAgentId());
+    }
+    
+    @Test
+    public void canGetMetadataFirstThreadStateForThread() {
+        PreparedParameter str1 = new PreparedParameter();
+        str1.setType(String.class);
+        str1.setValue("foo-agent");
+        PreparedParameter str2 = new PreparedParameter();
+        str2.setType(String.class);
+        str2.setValue("something");
+        PreparedParameter[] params = new PreparedParameter[] {
+                str1, str2
+        };
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_FIRST_THREAD_STATE_FOR_THREAD, params);
+        assertNotNull(data);
+        assertEquals("foo-agent", data.getAgentId());
+        assertFalse(data.hasVmId());
+        assertTrue(data.hasAgentId());
+        assertNull(data.getVmId());
+    }
+
+
+    @Test
+    public void canGetMetadataOldestThreadState() {
+        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
+
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_OLDEST_THREAD_STATE, triple.third);
+        assertThreadMetadata(triple, data);
+    }
+
+    @Test
+    public void canGetMetadataLatestThreadState() {
+        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
+
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_THREAD_STATE, triple.third);
+        assertThreadMetadata(triple, data);
+    }
+
+    @Test
+    public void canGetMetadataThreadStatePerThread() {
+        PreparedParameter str1 = new PreparedParameter();
+        str1.setType(String.class);
+        str1.setValue("foo");
+        PreparedParameter long1 = new PreparedParameter();
+        long1.setType(long.class);
+        long1.setValue(1L);
+        PreparedParameter long2 = new PreparedParameter();
+        long2.setType(long.class);
+        long2.setValue(2L);
+        PreparedParameter[] params = new PreparedParameter[] {
+                str1, long1, long2
+        };
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_THREAD_STATE_PER_THREAD, params);
+        assertNotNull(data);
+        assertNull(data.getAgentId());
+        assertNull(data.getVmId());
+    }
+    
+    @Test
+    public void canGetMetadataThreadLatestContentionSample() {
+        PreparedParameter str1 = new PreparedParameter();
+        str1.setType(String.class);
+        str1.setValue("foo");
+        PreparedParameter[] params = new PreparedParameter[] {
+                str1
+        };
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE, params);
+        assertNotNull(data);
+        assertFalse(data.hasAgentId());
+        assertFalse(data.hasVmId());
+        assertNull(data.getAgentId());
+        assertNull(data.getVmId());
+    }
+
+    @Test
+    public void unknownDescriptorThrowsException() {
+        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
+        try {
+            factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null);
+            fail("should have thrown exception");
+        } catch (IllegalArgumentException e) {
+            // pass
+        }
+    }
+}
+
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,275 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl;
-
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.auth.DescriptorMetadata;
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory;
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
-import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ThreadDAOImplStatementDescriptorRegistrationTest {
-
-    static class Triple<S, T, U> {
-        final S first;
-        final T second;
-        final U third;
-
-        public Triple(S first, T second, U third) {
-            this.first = first;
-            this.second = second;
-            this.third = third;
-        }
-    }
-    
-    @Test
-    public void registersAllDescriptors() {
-        ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration();
-        Set<String> descriptors = reg.getStatementDescriptors();
-        assertEquals(19, descriptors.size());
-        assertFalse("null descriptor not allowed", descriptors.contains(null));
-    }
-    
-    /*
-     * The web storage end-point uses service loader in order to determine the
-     * list of trusted/known registrations. This test is to ensure service loading
-     * works for this module's regs. E.g. renaming of the impl class without
-     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
-     */
-    @Test
-    public void serviceLoaderCanLoadRegistration() {
-        Set<String> expectedClassNames = new HashSet<>();
-        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
-        expectedClassNames.add(ThreadDaoImplStatementDescriptorRegistration.class.getName());
-        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, ThreadDaoImplStatementDescriptorRegistration.class.getClassLoader());
-        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
-        StatementDescriptorRegistration threadDaoReg = null;
-        for (StatementDescriptorRegistration r: loader) {
-            assertTrue(expectedClassNames.contains(r.getClass().getName()));
-            if (r.getClass().getName().equals(ThreadDaoImplStatementDescriptorRegistration.class.getName())) {
-                threadDaoReg = r;
-            }
-            registrations.add(r);
-        }
-        // storage-core + this module
-        assertEquals(2, registrations.size());
-        assertNotNull(threadDaoReg);
-        assertEquals(19, threadDaoReg.getStatementDescriptors().size());
-    }
-    
-    private Triple<String, String, PreparedParameter[]> setupForMetaDataTest() {
-        PreparedParameter agentIdParam = mock(PreparedParameter.class);
-        PreparedParameter vmIdParam = mock(PreparedParameter.class);
-        String agentId = "agentId";
-        String vmId = "vmId";
-        when(agentIdParam.getValue()).thenReturn(agentId);
-        when(vmIdParam.getValue()).thenReturn(vmId);
-        PreparedParameter[] params = new PreparedParameter[] { agentIdParam,
-                vmIdParam };
-        return new Triple<String, String, PreparedParameter[]>(agentId, vmId,
-                params);
-    }
-
-    private void assertThreadMetadata(
-            Triple<String, String, PreparedParameter[]> triple,
-            DescriptorMetadata data) {
-        assertNotNull(data);
-        assertEquals(triple.first, data.getAgentId());
-        assertEquals(triple.second, data.getVmId());
-    }
-    
-    @Test
-    public void canGetMetadataForLatestDeadlockQuery() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest(); 
-        
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-
-    @Test
-    public void canGetMetadataForLatestHarvestingStatusQuery() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest(); 
-        
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-
-    @Test
-    public void canGetMetadataForThreadHeader() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
-
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_THREAD_HEADER, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-
-    @Test
-    public void canGetMetadataAllThreadHeaders() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
-
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_ALL_THREAD_HEADERS, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-
-    @Test
-    public void canGetMetadataLastThreadStateForThread() {
-        PreparedParameter str1 = new PreparedParameter();
-        str1.setType(String.class);
-        str1.setValue("foo-agent");
-        PreparedParameter str2 = new PreparedParameter();
-        str2.setType(String.class);
-        str2.setValue("something");
-        PreparedParameter[] params = new PreparedParameter[] {
-                str1, str2
-        };
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_THREAD_STATE_FOR_THREAD, params);
-        assertNotNull(data);
-        assertEquals("foo-agent", data.getAgentId());
-        assertFalse(data.hasVmId());
-        assertTrue(data.hasAgentId());
-    }
-    
-    @Test
-    public void canGetMetadataFirstThreadStateForThread() {
-        PreparedParameter str1 = new PreparedParameter();
-        str1.setType(String.class);
-        str1.setValue("foo-agent");
-        PreparedParameter str2 = new PreparedParameter();
-        str2.setType(String.class);
-        str2.setValue("something");
-        PreparedParameter[] params = new PreparedParameter[] {
-                str1, str2
-        };
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_FIRST_THREAD_STATE_FOR_THREAD, params);
-        assertNotNull(data);
-        assertEquals("foo-agent", data.getAgentId());
-        assertFalse(data.hasVmId());
-        assertTrue(data.hasAgentId());
-        assertNull(data.getVmId());
-    }
-
-
-    @Test
-    public void canGetMetadataOldestThreadState() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
-
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_OLDEST_THREAD_STATE, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-
-    @Test
-    public void canGetMetadataLatestThreadState() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
-
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_THREAD_STATE, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-
-    @Test
-    public void canGetMetadataThreadStatePerThread() {
-        PreparedParameter str1 = new PreparedParameter();
-        str1.setType(String.class);
-        str1.setValue("foo");
-        PreparedParameter long1 = new PreparedParameter();
-        long1.setType(long.class);
-        long1.setValue(1L);
-        PreparedParameter long2 = new PreparedParameter();
-        long2.setType(long.class);
-        long2.setValue(2L);
-        PreparedParameter[] params = new PreparedParameter[] {
-                str1, long1, long2
-        };
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_THREAD_STATE_PER_THREAD, params);
-        assertNotNull(data);
-        assertNull(data.getAgentId());
-        assertNull(data.getVmId());
-    }
-    
-    @Test
-    public void canGetMetadataThreadLatestContentionSample() {
-        PreparedParameter str1 = new PreparedParameter();
-        str1.setType(String.class);
-        str1.setValue("foo");
-        PreparedParameter[] params = new PreparedParameter[] {
-                str1
-        };
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE, params);
-        assertNotNull(data);
-        assertFalse(data.hasAgentId());
-        assertFalse(data.hasVmId());
-        assertNull(data.getAgentId());
-        assertNull(data.getVmId());
-    }
-
-    @Test
-    public void unknownDescriptorThrowsException() {
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        try {
-            factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null);
-            fail("should have thrown exception");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-    }
-}
-
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategoriesTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategoriesTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -37,29 +37,47 @@
 package com.redhat.thermostat.thread.dao.impl;
 
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.Pojo;
+import com.redhat.thermostat.thread.dao.impl.statement.support.Category;
+import com.redhat.thermostat.thread.dao.impl.statement.support.CategoryBuilder;
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
-import junit.framework.TestCase;
+import org.junit.Test;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-public class ThreadDaoCategoriesTest extends TestCase {
+public class ThreadDaoCategoriesTest {
 
+    @Test
     public void testRegister() throws Exception {
         Set<String> set = new HashSet<>();
         ThreadDaoCategories.register(set);
 
-        // no real need to check all, but adding more doesn't hurt
-        assertTrue(set.contains(ThreadDaoCategories.THREAD_SESSION.getName()));
-        assertTrue(set.contains(ThreadDaoCategories.THREAD_SUMMARY.getName()));
+        assertEquals(ThreadDaoCategories.BEANS.size(), set.size());
+        for (Class<? extends Pojo> categoryClass : ThreadDaoCategories.BEANS) {
+            String name = categoryClass.getAnnotation(Category.class).value();
+            assertTrue(set.contains(name));
+        }
     }
 
+    @Test
     public void testRegisterInStorage() throws Exception {
         Storage storage = mock(Storage.class);
-        ThreadDaoCategories.register(storage);
 
-        verify(storage).registerCategory(ThreadDaoCategories.THREAD_SESSION);
-        verify(storage).registerCategory(ThreadDaoCategories.THREAD_SUMMARY);
+        List<com.redhat.thermostat.storage.core.Category<?>> categories =
+                new ArrayList<>();
+        for (Class<? extends Pojo> categoryClass : ThreadDaoCategories.BEANS) {
+            categories.add(new CategoryBuilder(categoryClass).build());
+        }
+
+        ThreadDaoCategories.register(storage);
+        for (com.redhat.thermostat.storage.core.Category<?> category : categories) {
+            verify(storage).registerCategory(category);
+        }
     }
 }
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -163,7 +163,6 @@
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         
         verify(storage).registerCategory(ThreadDao.THREAD_HARVESTING_STATUS);
-        verify(storage).registerCategory(ThreadDaoCategories.THREAD_SUMMARY);
     }
 
     @SuppressWarnings("unchecked")
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/DescriptorTester.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.testutils.StatementDescriptorTester;
-
-/**
- *
- */
-public class DescriptorTester {
-
-    public static <C extends Pojo> void testStatement(Category<C> category, String statement) throws Exception {
-
-        StatementDescriptorTester<C> tester = new StatementDescriptorTester<>();
-        StatementDescriptor<C> desc = new StatementDescriptor<>(category, statement);
-        tester.testParseBasic(desc);
-        tester.testParseSemantic(desc);
-    }
-}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorBuilderTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
-import junit.framework.TestCase;
-import org.junit.Test;
-
-public class SummaryDescriptorBuilderTest extends TestCase {
-
-    @Test
-    public void testBuild() {
-        SummaryDescriptor summary = new SummaryDescriptorBuilder().build();
-        assertNotNull(summary);
-    }
-
-    @Test
-    public void testCategory() {
-        SummaryDescriptor summary = new SummaryDescriptorBuilder().build();
-        assertEquals(ThreadDaoCategories.THREAD_SUMMARY, summary.getCategory());
-    }
-
-    @Test
-    public void testAddDesc() throws Exception {
-        SummaryDescriptor summary = new SummaryDescriptorBuilder().build();
-        DescriptorTester.testStatement(summary.getCategory(), summary.addDesc);
-    }
-
-    @Test
-    public void testRangeDesc() throws Exception {
-
-        SummaryDescriptor summary = new SummaryDescriptorBuilder().build();
-        DescriptorTester.testStatement(summary.getCategory(), summary.rangeDesc);
-    }
-}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-
-public class SummaryDescriptorTest extends TestCase {
-
-    private SummaryDescriptor descriptor;
-    @Before
-    public void setUp() {
-        descriptor = new SummaryDescriptorBuilder().build();
-    }
-
-    public void testGetSummaryRange() throws Exception {
-
-        String expected =
-                "QUERY vm-thread-summary WHERE 'session' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i";
-        assertEquals(expected, descriptor.rangeDesc);
-    }
-
-    public void testAddSummary() throws Exception {
-
-        String expected =
-                "ADD vm-thread-summary SET 'agentId' = ?s , 'vmId' = ?s , 'session' = ?s , 'currentLiveThreads' = ?l , 'currentDaemonThreads' = ?l , 'timeStamp' = ?l";
-        assertEquals(expected, descriptor.addDesc);
-
-    }
-}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptorBuilderTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
-import junit.framework.TestCase;
-import org.junit.Test;
-
-public class ThreadSessionDescriptorBuilderTest extends TestCase {
-
-    @Test
-    public void testBuild() {
-        ThreadSessionDescriptor descriptor = new ThreadSessionDescriptorBuilder().build();
-        assertNotNull(descriptor);
-    }
-
-    @Test
-    public void testCategory() {
-        ThreadSessionDescriptor descriptor = new ThreadSessionDescriptorBuilder().build();
-        assertEquals(ThreadDaoCategories.THREAD_SESSION, descriptor.getCategory());
-    }
-
-    @Test
-    public void testQuerySessions() throws Exception {
-        ThreadSessionDescriptor descriptor = new ThreadSessionDescriptorBuilder().build();
-        DescriptorTester.testStatement(descriptor.getCategory(), descriptor.querySessions);
-    }
-
-    @Test
-    public void testStatementAdd() throws Exception {
-        ThreadSessionDescriptor descriptor = new ThreadSessionDescriptorBuilder().build();
-        DescriptorTester.testStatement(descriptor.getCategory(), descriptor.statementAdd);
-    }
-}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/ThreadSessionDescriptorTest.java	Tue Nov 18 16:03:17 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2014 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.thread.dao.impl.descriptor;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-
-public class ThreadSessionDescriptorTest extends TestCase {
-
-    private ThreadSessionDescriptor descriptor;
-
-    @Before
-    public void setUp() {
-        descriptor = new ThreadSessionDescriptorBuilder().build();
-    }
-
-    public void testQuerySessions() throws Exception {
-        String expected =
-                "QUERY vm-thread-session WHERE 'vmId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i";
-        assertEquals(expected, descriptor.querySessions);
-    }
-
-    public void testStatementAdd() throws Exception {
-        String expected =
-                "ADD vm-thread-session SET 'agentId' = ?s , 'vmId' = ?s , 'session' = ?s , 'timeStamp' = ?l";
-        assertEquals(expected, descriptor.statementAdd);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/SessionQueryTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement;
+
+import com.redhat.thermostat.thread.dao.impl.statement.support.BeanAdapter;
+import com.redhat.thermostat.thread.dao.impl.statement.support.BeanAdapterBuilder;
+import com.redhat.thermostat.thread.model.ThreadSession;
+import java.util.Set;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+public class SessionQueryTest {
+
+    @Test
+    public void testDescribe() throws Exception {
+        BeanAdapter<ThreadSession> session =
+                new BeanAdapterBuilder<>(ThreadSession.class,
+                                         new SessionQuery()).build();
+        Set<String> statements = session.describeStatements();
+        assertEquals(2, statements.size());
+
+        String expected = "QUERY vm-thread-session WHERE 'vmId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DESC LIMIT ?i";
+        assertTrue(statements.contains(expected));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/SummaryQueryTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement;
+
+import com.redhat.thermostat.thread.dao.impl.statement.support.BeanAdapter;
+import com.redhat.thermostat.thread.dao.impl.statement.support.BeanAdapterBuilder;
+import com.redhat.thermostat.thread.model.ThreadSummary;
+import java.util.Set;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+public class SummaryQueryTest {
+    @Test
+    public void testDescribe() throws Exception {
+        BeanAdapter<ThreadSummary> session =
+                new BeanAdapterBuilder<>(ThreadSummary.class,
+                                         new SummaryQuery()).build();
+        Set<String> statements = session.describeStatements();
+        assertEquals(2, statements.size());
+
+        String expected = "QUERY vm-thread-summary WHERE 'vmId' = ?s AND 'session' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DESC LIMIT ?i";
+        assertTrue(statements.contains(expected));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapterBuilderTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class BeanAdapterBuilderTest {
+
+    @Category("testCategory")
+    private static class SampleBean implements TimeStampedPojo {
+
+        private long timeStamp;
+        private int vmId;
+        private String name;
+
+        @Indexed
+        @Persist
+        public int getVmId() {
+            return vmId;
+        }
+
+        @Indexed
+        @Persist
+        public void setVmId(int vmId) {
+            this.vmId = vmId;
+        }
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @Indexed
+        @Persist
+        public void setTimeStamp(long timeStamp) {
+            this.timeStamp = timeStamp;
+        }
+
+        @Indexed
+        @Persist
+        @Override
+        public long getTimeStamp() {
+            return timeStamp;
+        }
+    }
+
+    private List<Query<SampleBean>> queries;
+
+    @Before
+    public void setUp() {
+        queries = new ArrayList<>();
+
+        List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(SampleBean.class);
+        final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors);
+        Query query = new Query<SampleBean>() {
+            @Override
+            protected void describe(Criteria criterias) {
+                criterias.add(new WhereCriterion(new Id("name"), map.get("name"), TypeMapper.Criteria.Equal));
+                criterias.add(new WhereCriterion(new Id("vmId>="), map.get("vmId"), TypeMapper.Criteria.GreaterEqual));
+                criterias.add(new WhereCriterion(new Id("vmId<="), map.get("vmId"), TypeMapper.Criteria.LessEqual));
+                criterias.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending));
+                criterias.add(new LimitCriterion(new Id("limit")));
+            }
+
+            @Override
+            public Id getId() {
+                return new Id("SortByTimeStamp");
+            }
+        };
+        queries.add(query);
+
+        query = new Query<SampleBean>() {
+            @Override
+            protected void describe(Criteria criterias) {
+                criterias.add(new WhereCriterion(new Id("name"), map.get("name"), TypeMapper.Criteria.Equal));
+                criterias.add(new WhereCriterion(new Id("timeStamp>="), map.get("timeStamp"), TypeMapper.Criteria.GreaterEqual));
+                criterias.add(new WhereCriterion(new Id("timeStamp<="), map.get("timeStamp"), TypeMapper.Criteria.LessEqual));
+                criterias.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending));
+                criterias.add(new LimitCriterion(new Id("limit")));
+            }
+
+            @Override
+            public Id getId() {
+                return new Id("RangedQuery");
+            }
+        };
+        queries.add(query);
+    }
+
+    @Test
+    public void testBeanAdapterBuilder() throws Exception {
+
+        BeanAdapterBuilder<SampleBean> builder =
+                new BeanAdapterBuilder<>(SampleBean.class, queries);
+
+        BeanAdapter<SampleBean> adapter = builder.build();
+        assertNotNull(adapter);
+
+        com.redhat.thermostat.storage.core.Category<SampleBean> category =
+                adapter.getCategory();
+
+        assertNotNull(category);
+        assertEquals("testCategory", category.getName());
+
+        String expected = "ADD testCategory SET 'name' = ?s , 'timeStamp' = ?l , 'vmId' = ?i";
+        Set<String> statements = adapter.describeStatements();
+
+        assertEquals(3, statements.size());
+        assertTrue(statements.contains(expected));
+
+        expected = "QUERY testCategory WHERE 'name' = ?s AND 'vmId' >= ?i AND 'vmId' <= ?i SORT 'timeStamp' ASC LIMIT ?i";
+        assertTrue(statements.contains(expected));
+
+        expected = "QUERY testCategory WHERE 'name' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' ASC LIMIT ?i";
+        assertTrue(statements.contains(expected));
+
+        for (String s : statements) {
+            DescriptorTester.testStatement(category, s);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/BeanAdapterTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class BeanAdapterTest {
+
+    @com.redhat.thermostat.thread.dao.impl.statement.support.Category("testCategory")
+    private static class SampleBean implements TimeStampedPojo {
+
+        private long timeStamp;
+        private int vmId;
+        private String name;
+
+        @Indexed
+        @Persist
+        public int getVmId() {
+            return vmId;
+        }
+
+        @Indexed
+        @Persist
+        public void setVmId(int vmId) {
+            this.vmId = vmId;
+        }
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @Indexed
+        @Persist
+        public void setTimeStamp(long timeStamp) {
+            this.timeStamp = timeStamp;
+        }
+
+        @Indexed
+        @Persist
+        @Override
+        public long getTimeStamp() {
+            return timeStamp;
+        }
+    }
+
+    private Storage storage;
+    private PreparedStatement<SampleBean> insert;
+    private PreparedStatement<SampleBean> query;
+
+    private List<Query<SampleBean>> queries;
+
+    private static final Id SORT = new Id("SortByTimeStamp");
+    private static final Id RANGE = new Id("RangedQuery");
+
+    @Before
+    public void setUp() throws Exception {
+        storage = mock(Storage.class);
+        insert = mock(PreparedStatement.class);
+        query = mock(PreparedStatement.class);
+
+        queries = new ArrayList<>();
+
+        List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(SampleBean.class);
+        final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors);
+        Query query = new Query<SampleBean>() {
+            @Override
+            protected void describe(Criteria criterias) {
+                criterias.add(new WhereCriterion(new Id("0"), map.get("name"), TypeMapper.Criteria.Equal));
+                criterias.add(new WhereCriterion(new Id("1"), map.get("vmId"), TypeMapper.Criteria.GreaterEqual));
+                criterias.add(new WhereCriterion(new Id("2"), map.get("vmId"), TypeMapper.Criteria.LessEqual));
+                criterias.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending));
+                criterias.add(new LimitCriterion(new Id("3")));
+            }
+
+            @Override
+            public Id getId() {
+                return SORT;
+            }
+        };
+        queries.add(query);
+
+        query = new Query<SampleBean>() {
+            @Override
+            protected void describe(Criteria criterias) {
+                criterias.add(new WhereCriterion(new Id("0"), map.get("name"), TypeMapper.Criteria.Equal));
+                criterias.add(new WhereCriterion(new Id("1"), map.get("timeStamp"), TypeMapper.Criteria.GreaterEqual));
+                criterias.add(new WhereCriterion(new Id("2"), map.get("timeStamp"), TypeMapper.Criteria.LessEqual));
+                criterias.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending));
+                criterias.add(new LimitCriterion(new Id("3")));
+            }
+
+            @Override
+            public Id getId() {
+                return RANGE;
+            }
+        };
+        queries.add(query);
+    }
+
+    @Test
+    public void testHasQueries() throws Exception {
+        BeanAdapterBuilder<SampleBean> builder =
+                new BeanAdapterBuilder<>(SampleBean.class, queries);
+
+        BeanAdapter<SampleBean> adapter = builder.build();
+
+        Query query = adapter.getQuery(SORT);
+        assertSame(queries.get(0), query);
+
+        query = adapter.getQuery(RANGE);
+        assertSame(queries.get(1), query);
+    }
+
+    @Test
+    public void testInsert() throws Exception {
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(insert);
+
+        BeanAdapterBuilder<SampleBean> builder =
+                new BeanAdapterBuilder<>(SampleBean.class, queries);
+
+        BeanAdapter<SampleBean> adapter = builder.build();
+
+        SampleBean bean = new SampleBean();
+        bean.setName("fluff");
+        bean.setTimeStamp(1000l);
+        bean.setVmId(0xcafe);
+
+        adapter.insert(bean, storage);
+
+        verify(storage).prepareStatement(any(StatementDescriptor.class));
+
+        // the order is given by the bean methods, they are sorted in
+        // alphabetical order, this is not really important though,
+        // since the order is based on the same FieldDescriptors used by
+        // both the builder and the adapter, so it's transparent to the user
+
+        verify(insert).setString(0, "fluff");
+        verify(insert).setLong(1, 1000l);
+        verify(insert).setInt(2, 0xcafe);
+
+        verify(insert).execute();
+        verifyNoMoreInteractions(insert);
+    }
+
+    @Test
+    public void testSortQuery() throws Exception {
+
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(query);
+        Cursor cursor = mock(Cursor.class);
+        SampleBean sample = mock(SampleBean.class);
+        when(query.executeQuery()).thenReturn(cursor);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(sample);
+
+        BeanAdapterBuilder<SampleBean> builder =
+                new BeanAdapterBuilder<>(SampleBean.class, queries);
+
+        BeanAdapter<SampleBean> adapter = builder.build();
+        Query sort = adapter.getQuery(SORT);
+        assertNotNull(sort);
+        assertSame(sort, queries.get(0));
+
+        QueryValues values = sort.createValues();
+        values.set(new Id("0"), "fluff");
+        values.set(new Id("1"), 5);
+        values.set(new Id("2"), 5);
+        values.set(new Id("3"), 2);
+
+        final boolean [] called = new boolean[1];
+        ResultHandler<SampleBean> handler = new ResultHandler<SampleBean>() {
+            @Override
+            public void onResult(SampleBean result) {
+                called[0] = true;
+            }
+        };
+
+        adapter.query(values, handler, storage);
+
+        verify(query).setString(0, "fluff");
+        verify(query).setInt(1, 5);
+        verify(query).setInt(2, 5);
+        verify(query).setInt(3, 2);
+
+        assertTrue(called[0]);
+    }
+
+    @Test
+    public void testRangeQuery() throws Exception {
+
+        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(query);
+        Cursor cursor = mock(Cursor.class);
+        SampleBean sample = mock(SampleBean.class);
+        when(query.executeQuery()).thenReturn(cursor);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(sample);
+
+        BeanAdapterBuilder<SampleBean> builder =
+                new BeanAdapterBuilder<>(SampleBean.class, queries);
+
+        BeanAdapter<SampleBean> adapter = builder.build();
+        Query range = adapter.getQuery(RANGE);
+        assertNotNull(range);
+        assertSame(range, queries.get(1));
+
+        QueryValues values = range.createValues();
+        values.set(new Id("0"), "fluff");
+        values.set(new Id("1"), 10l);
+        values.set(new Id("2"), 20l);
+        values.set(new Id("3"), 2);
+
+        final boolean [] called = new boolean[1];
+        ResultHandler<SampleBean> handler = new ResultHandler<SampleBean>() {
+            @Override
+            public void onResult(SampleBean result) {
+                called[0] = true;
+            }
+        };
+
+        adapter.query(values, handler, storage);
+
+        verify(query).setString(0, "fluff");
+        verify(query).setLong(1, 10);
+        verify(query).setLong(2, 20);
+        verify(query).setInt(3, 2);
+
+        assertTrue(called[0]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/CategoryBuilderTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class CategoryBuilderTest {
+
+    private static final String CATEGORY_NAME = "builder-category-test";
+
+    @Category(CATEGORY_NAME)
+    private static class SampleBean implements TimeStampedPojo {
+
+        private long timeStamp;
+        private String vmId;
+        private String name;
+
+        @Indexed
+        @Persist
+        public String getVmId() {
+            return vmId;
+        }
+
+        @Indexed
+        @Persist
+        public void setVmId(String vmId) {
+            this.vmId = vmId;
+        }
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @Indexed
+        @Persist
+        public void setTimeStamp(long timeStamp) {
+            this.timeStamp = timeStamp;
+        }
+
+        @Indexed
+        @Persist
+        @Override
+        public long getTimeStamp() {
+            return timeStamp;
+        }
+    }
+
+    @Test
+    public void testBuild() throws Exception {
+        CategoryBuilder builder =  new CategoryBuilder(SampleBean.class);
+        com.redhat.thermostat.storage.core.Category<SampleBean> category =
+                builder.build();
+
+        assertNotNull(category);
+        assertEquals(CATEGORY_NAME, category.getName());
+        assertEquals(SampleBean.class, category.getDataClass());
+
+        List<Key<?>> indexed = category.getIndexedKeys();
+        assertEquals(2, indexed.size());
+
+        Key key0 = new Key("vmId");
+        Key key1 = new Key("timeStamp");
+
+        assertTrue(indexed.contains(key0));
+        assertTrue(indexed.contains(key1));
+
+        Collection<Key<?>> keys = category.getKeys();
+        assertEquals(3, keys.size());
+
+        Key key2 = new Key("name");
+
+        assertTrue(keys.contains(key0));
+        assertTrue(keys.contains(key1));
+        assertTrue(keys.contains(key2));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/DescriptorTester.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.model.Pojo;
+import com.redhat.thermostat.storage.testutils.StatementDescriptorTester;
+
+/**
+ *
+ */
+public class DescriptorTester {
+
+    public static <C extends Pojo> void testStatement(Category<C> category, String statement) throws Exception {
+
+        StatementDescriptorTester<C> tester = new StatementDescriptorTester<>();
+        StatementDescriptor<C> desc = new StatementDescriptor<>(category, statement);
+        tester.testParseBasic(desc);
+        tester.testParseSemantic(desc);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/InsertEngineTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class InsertEngineTest {
+    private com.redhat.thermostat.storage.core.Category category;
+    private FieldDescriptor descriptor0;
+    private FieldDescriptor descriptor1;
+    private FieldDescriptor descriptor2;
+
+    @Before
+    public void setup() {
+        category = mock(com.redhat.thermostat.storage.core.Category.class);
+        when(category.getName()).thenReturn("testCategory");
+
+        descriptor0 = mock(FieldDescriptor.class);
+        when(descriptor0.getName()).thenReturn("descriptor0");
+        Class type = String.class;
+        when(descriptor0.getType()).thenReturn(type);
+
+        descriptor1 = mock(FieldDescriptor.class);
+        when(descriptor1.getName()).thenReturn("descriptor1");
+        type = long.class;
+        when(descriptor1.getType()).thenReturn(type);
+
+        descriptor2 = mock(FieldDescriptor.class);
+        when(descriptor2.getName()).thenReturn("descriptor2");
+        type = int.class;
+        when(descriptor2.getType()).thenReturn(type);
+    }
+
+    @Test
+    public void testBuildInsert() throws Exception {
+        InsertEngine engine = new InsertEngine();
+
+        engine.prologue(category);
+        engine.add(descriptor0);
+        engine.add(descriptor1);
+        engine.add(descriptor2);
+
+        Statement statement = engine.build();
+
+        String expected = "ADD testCategory SET 'descriptor0' = ?s , 'descriptor1' = ?l , 'descriptor2' = ?i";
+        assertEquals(expected, statement.get());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryEngineTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class QueryEngineTest {
+    private com.redhat.thermostat.storage.core.Category category;
+    private FieldDescriptor descriptor0;
+    private FieldDescriptor descriptor1;
+    private FieldDescriptor descriptor2;
+
+    @Before
+    public void setup() {
+        category = mock(com.redhat.thermostat.storage.core.Category.class);
+        when(category.getName()).thenReturn("testCategory");
+
+        descriptor0 = mock(FieldDescriptor.class);
+        when(descriptor0.getName()).thenReturn("descriptor0");
+        Class type = String.class;
+        when(descriptor0.getType()).thenReturn(type);
+
+        descriptor1 = mock(FieldDescriptor.class);
+        when(descriptor1.getName()).thenReturn("descriptor1");
+        type = long.class;
+        when(descriptor1.getType()).thenReturn(type);
+
+        descriptor2 = mock(FieldDescriptor.class);
+        when(descriptor2.getName()).thenReturn("descriptor2");
+        type = int.class;
+        when(descriptor2.getType()).thenReturn(type);
+    }
+
+    @Test
+    public void testBuildQuery() throws Exception {
+        QueryEngine engine = new QueryEngine();
+
+        engine.prologue(category);
+        engine.add(descriptor0, TypeMapper.Criteria.Equal);
+        engine.add(descriptor1, TypeMapper.Criteria.GreaterEqual);
+        engine.add(descriptor2, TypeMapper.Criteria.LessEqual);
+
+        engine.limit();
+        engine.sort(descriptor1, TypeMapper.Sort.Ascending);
+
+        Statement statement = engine.build();
+
+        String expected = "QUERY testCategory WHERE 'descriptor0' = ?s AND 'descriptor1' >= ?l AND 'descriptor2' <= ?i SORT 'descriptor1' ASC LIMIT ?i";
+
+        assertEquals(expected, statement.get());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/QueryValuesTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class QueryValuesTest {
+
+    private Query query;
+    private List<Criterion> criterias;
+
+    private Criterion criterion0;
+    private Criterion criterion1;
+    private Criterion criterion2;
+
+    @Before
+    public void setup() {
+        query = mock(Query.class);
+        criterias = new ArrayList<>();
+
+        criterion0 = mock(Criterion.class);
+        when(criterion0.getType()).thenReturn((Class)  int.class);
+        when(criterion0.getId()).thenReturn(new Id("0"));
+
+        criterion1 = mock(Criterion.class);
+        when(criterion1.getType()).thenReturn((Class) String.class);
+        when(criterion1.getId()).thenReturn(new Id("1"));
+
+        criterion2 = mock(Criterion.class);
+        when(criterion2.getType()).thenReturn((Class) long.class);
+        when(criterion2.getId()).thenReturn(new Id("2"));
+
+        criterias.add(criterion0);
+        criterias.add(criterion1);
+        criterias.add(criterion2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetWithWrongArguments() throws Exception {
+
+        QueryValues values = new QueryValues(query);
+        values.addCriteria(criterias);
+
+        values.set(criterion0, "wrong type");
+    }
+
+    @Test
+    public void testSet() throws Exception {
+
+        QueryValues values = new QueryValues(query);
+        values.addCriteria(criterias);
+
+        values.set(criterion0, 10);
+        values.set(criterion1, "test");
+        values.set(criterion2, 42l);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class StatementTest {
+
+    @Test
+    public void testEquals() throws Exception {
+        Statement statement = new Statement("test");
+        Statement statement2 = new Statement("test");
+
+        assertTrue(statement.equals("test"));
+        assertTrue(statement.equals(statement2));
+
+        statement2 = new Statement("fluff");
+        assertFalse(statement.equals("fluff"));
+        assertFalse(statement.equals(statement2));
+    }
+
+    @Test
+    public void testHashCode() throws Exception {
+        Statement statement = new Statement("test");
+        Statement statement2 = new Statement("test");
+
+        assertEquals(statement.hashCode(), statement2.hashCode());
+
+        statement2 = new Statement("fluff");
+        assertFalse(statement.hashCode() == statement2.hashCode());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/support/StatementUtilsTest.java	Tue Nov 18 16:03:34 2014 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2012-2014 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl.statement.support;
+
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class StatementUtilsTest {
+
+    @Category("testCategory")
+    private static class SampleBean implements TimeStampedPojo {
+
+        private long timeStamp;
+        private int vmId;
+        private String name;
+
+        @Indexed
+        @Persist
+        public int getVmId() {
+            return vmId;
+        }
+
+        @Indexed
+        @Persist
+        public void setVmId(int vmId) {
+            this.vmId = vmId;
+        }
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @Indexed
+        @Persist
+        public void setTimeStamp(long timeStamp) {
+            this.timeStamp = timeStamp;
+        }
+
+        @Indexed
+        @Persist
+        @Override
+        public long getTimeStamp() {
+            return timeStamp;
+        }
+    }
+
+    @Category("testCategory2")
+    private static class InvalidSampleBean implements TimeStampedPojo {
+
+        private long timeStamp;
+        private int vmId;
+        private String name;
+
+        public int getVmId() {
+            return vmId;
+        }
+
+        @Indexed
+        @Persist
+        public void setVmId(int vmId) {
+            this.vmId = vmId;
+        }
+
+        @Persist
+        public String getName() {
+            return name;
+        }
+
+        @Persist
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public void setTimeStamp(long timeStamp) {
+            this.timeStamp = timeStamp;
+        }
+
+        @Indexed
+        @Persist
+        @Override
+        public long getTimeStamp() {
+            return timeStamp;
+        }
+    }
+
+    @Test
+    public void testAnnotationSupport() {
+        List<FieldDescriptor> descriptors =
+                StatementUtils.createDescriptors(SampleBean.class);
+        Map<String, FieldDescriptor> map =
+                StatementUtils.createDescriptorMap(descriptors);
+
+        assertTrue(map.containsKey("timeStamp"));
+
+        descriptors =  StatementUtils.createDescriptors(InvalidSampleBean.class);
+        map = StatementUtils.createDescriptorMap(descriptors);
+
+        assertFalse(map.containsKey("timeStamp"));
+    }
+}
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadSessionHelper.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadSessionHelper.java	Tue Nov 18 16:03:34 2014 +0100
@@ -62,7 +62,7 @@
     ThreadSession createSession() {
         ThreadSession session = new ThreadSession();
 
-        session.setSession(new SessionID().getId());
+        session.setSession(new SessionID().get());
         session.setTimeStamp(clock.getRealTimeMillis());
         session.setVmId(vmId);
         session.setAgentId(writerId.getWriterID());
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.java	Tue Nov 18 16:03:17 2014 +0100
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.java	Tue Nov 18 16:03:34 2014 +0100
@@ -97,7 +97,7 @@
         VmStatusListenerRegistrar vmListener = new VmStatusListenerRegistrar(context);
 
         /*
-         * dont register anything just yet, let the backend handle the
+         * dont register anything just yet, let the backend onResult the
          * registration, deregistration it when it's activated or deactivated
          */