changeset 1545:722862a0c335

Compiler project for prepared statement - part I 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:02:57 +0100
parents d318a5be8867
children 32255ddb2c4c
files thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountController.java thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountControllerTest.java thread/collector/pom.xml thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistration.java 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/model/SessionID.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadPojo.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistrationTest.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/ThreadDaoImplTest.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/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/HarvesterHelper.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadStateHelper.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadSummaryHelper.java thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterHelperTest.java thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadHarvesterTest.java thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadSummaryHelperTest.java
diffstat 31 files changed, 948 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java	Tue Nov 18 16:02:57 2014 +0100
@@ -39,6 +39,7 @@
 import com.redhat.thermostat.common.model.Range;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadContentionSample;
 import com.redhat.thermostat.thread.model.ThreadHeader;
 import com.redhat.thermostat.thread.model.ThreadState;
@@ -54,9 +55,12 @@
     boolean startHarvester();
     boolean stopHarvester();
     boolean isHarvesterCollecting();
-    
-    ThreadSummary getLatestThreadSummary();
-    List<ThreadSummary> getThreadSummary(long since);
+
+    List<SessionID> getAvailableThreadSummarySessions(Range<Long> range);
+    SessionID getLastThreadSummarySession();
+
+    ThreadSummary getLatestThreadSummary(SessionID session);
+    List<ThreadSummary> getThreadSummary(SessionID session, Range<Long> range);
 
     /**
      * Return the range of all {@link ThreadState} data (timestamp of first and
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java	Tue Nov 18 16:02:57 2014 +0100
@@ -49,6 +49,7 @@
 import com.redhat.thermostat.thread.client.common.collector.ThreadCollector;
 import com.redhat.thermostat.thread.collector.HarvesterCommand;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadContentionSample;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.ThreadHeader;
@@ -131,14 +132,33 @@
         }
         return status.isHarvesting();
     }
-    
+
+    @Override
+    public List<SessionID> getAvailableThreadSummarySessions(Range<Long> range) {
+        return threadDao.getAvailableThreadSummarySessions(ref, range, Integer.MAX_VALUE);
+    }
+
     @Override
-    public ThreadSummary getLatestThreadSummary() {
-        ThreadSummary summary = threadDao.loadLastestSummary(ref);
-        if (summary == null) {
+    public SessionID getLastThreadSummarySession() {
+        List<SessionID> sessions =
+                threadDao.getAvailableThreadSummarySessions(ref,
+                                                            new Range<>(0l, Long.MAX_VALUE),
+                                                            1);
+        return sessions.isEmpty() ? null : sessions.get(0);
+    }
+
+    @Override
+    public ThreadSummary getLatestThreadSummary(SessionID session) {
+        List<ThreadSummary> summaries =
+                threadDao.getSummary(ref, session, new Range<>(0l, Long.MAX_VALUE), 1);
+        ThreadSummary summary = null;
+        if (summaries.isEmpty()) {
             // default to all 0
             summary = new ThreadSummary();
+        } else {
+            summary = summaries.get(0);
         }
+
         return summary;
     }
 
@@ -158,8 +178,8 @@
     }
 
     @Override
-    public List<ThreadSummary> getThreadSummary(long since) {
-        List<ThreadSummary> summary = threadDao.loadSummary(ref, since);
+    public List<ThreadSummary> getThreadSummary(SessionID session, Range<Long> range) {
+        List<ThreadSummary> summary = threadDao.getSummary(ref, session, range, Integer.MAX_VALUE);
         return summary;
     }
 
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountController.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountController.java	Tue Nov 18 16:02:57 2014 +0100
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.thread.client.controller.impl;
 
+import com.redhat.thermostat.common.model.Range;
+import com.redhat.thermostat.thread.model.SessionID;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -65,17 +67,24 @@
         @Override
         public void run() {
 
+            SessionID lastSession = collector.getLastThreadSummarySession();
+            if (lastSession == null) {
+                return;
+            }
+
             ThreadCountView view = (ThreadCountView) ThreadCountController.this.view;
             
             // load the very latest thread summary
-            ThreadSummary latestSummary = collector.getLatestThreadSummary();
+            ThreadSummary latestSummary = collector.getLatestThreadSummary(lastSession);
             if (latestSummary.getTimeStamp() != 0) {
                 view.setLiveThreads(Long.toString(latestSummary.getCurrentLiveThreads()));
                 view.setDaemonThreads(Long.toString(latestSummary.getCurrentDaemonThreads()));
             }
-            
+
+            long now = System.currentTimeMillis();
             long lastHour = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
-            List<ThreadSummary> summaries = collector.getThreadSummary(lastHour);
+
+            List<ThreadSummary> summaries = collector.getThreadSummary(lastSession, new Range<Long>(lastHour, now));
             if (summaries.size() != 0) {
                 for (ThreadSummary summary : summaries) {
                     model.addData(summary.getTimeStamp(), summary.getCurrentLiveThreads(), summary.getCurrentDaemonThreads());
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountControllerTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountControllerTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -36,20 +36,20 @@
 
 package com.redhat.thermostat.thread.client.controller.impl;
 
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.anyLong;
-
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.model.Range;
+import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart;
+import com.redhat.thermostat.thread.client.common.collector.ThreadCollector;
+import com.redhat.thermostat.thread.client.common.view.ThreadCountView;
+import com.redhat.thermostat.thread.model.SessionID;
+import com.redhat.thermostat.thread.model.ThreadSummary;
 import java.awt.Color;
 import java.util.ArrayList;
 import java.util.List;
-
-import static org.junit.Assert.*;
-
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
 import org.jfree.chart.JFreeChart;
 import org.jfree.data.xy.XYDataset;
 import org.junit.Before;
@@ -57,14 +57,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart;
-import com.redhat.thermostat.thread.client.common.collector.ThreadCollector;
-import com.redhat.thermostat.thread.client.common.view.ThreadCountView;
-import com.redhat.thermostat.thread.model.ThreadSummary;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 // this is not a GUI test, but testGetThreadInformation uses AWT under the hood 
 @RunWith(CacioFESTRunner.class)
@@ -110,13 +109,18 @@
         List<ThreadSummary> summaries = new ArrayList<>();
         summaries.add(summary);
         summaries.add(summary0);
-        
-        when(collector.getLatestThreadSummary()).thenReturn(summary);
-        when(collector.getThreadSummary(anyLong())).thenReturn(summaries);
-        
+
+        SessionID lastSession = mock(SessionID.class);
+        when(collector.getLastThreadSummarySession()).thenReturn(lastSession);
+
+        when(collector.getLatestThreadSummary(lastSession)).thenReturn(summary);
+        when(collector.getThreadSummary(any(SessionID.class), any(Range.class))).thenReturn(summaries);
+
         threadAction = captor.getValue();
         threadAction.run();
-        
+
+        verify(collector).getLatestThreadSummary(lastSession);
+
         verify(view).setLiveThreads("42");
         verify(view).setDaemonThreads("2");
         
--- a/thread/collector/pom.xml	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/pom.xml	Tue Nov 18 16:02:57 2014 +0100
@@ -76,7 +76,13 @@
       <artifactId>thermostat-client-command</artifactId>
       <version>${project.version}</version>
     </dependency>
-    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-storage-testutils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
@@ -115,6 +121,7 @@
             <Private-Package>
               com.redhat.thermostat.thread.common.osgi,
               com.redhat.thermostat.thread.dao.impl,
+              com.redhat.thermostat.thread.dao.impl.descriptor,
             </Private-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Tue Nov 18 16:02:57 2014 +0100
@@ -40,6 +40,7 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.VmRef;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadContentionSample;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.ThreadHeader;
@@ -59,21 +60,6 @@
     static final String THREAD_ALLOCATED_MEMORY = "thread-allocated-memory";
 
     /*
-     * vm-thread-summary schema
-     */
-    static final Key<Long> LIVE_THREADS_KEY = new Key<Long>("currentLiveThreads");
-    static final Key<Long> DAEMON_THREADS_KEY = new Key<Long>("currentDaemonThreads");
-    static final Category<ThreadSummary> THREAD_SUMMARY =
-            new Category<>("vm-thread-summary", ThreadSummary.class,
-                    Arrays.<Key<?>>asList(
-                            Key.AGENT_ID,
-                            Key.VM_ID,
-                            Key.TIMESTAMP,
-                            LIVE_THREADS_KEY,
-                            DAEMON_THREADS_KEY),
-                    Arrays.<Key<?>>asList(Key.TIMESTAMP));
-
-    /*
      * vm-thread-harvesting schema
      */
     static final Key<Boolean> HARVESTING_STATUS_KEY = new Key<Boolean>("harvesting");
@@ -145,13 +131,9 @@
                                                  THREAD_CONTENTION_WAITED_TIME_KEY,
                                                  THREAD_HEADER_UUID, Key.TIMESTAMP));
 
-    /*
-     * API methods
-     */
-    
     void saveSummary(ThreadSummary summary);
-    ThreadSummary loadLastestSummary(VmRef ref);
-    List<ThreadSummary> loadSummary(VmRef ref, long since);
+    List<ThreadSummary> getSummary(VmRef ref, SessionID session, Range<Long> range, int limit);
+    List<SessionID> getAvailableThreadSummarySessions(VmRef ref, Range<Long> range, int limit);
 
     /**
      * Gets the total time interval for the entire data related to
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistration.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistration.java	Tue Nov 18 16:02:57 2014 +0100
@@ -57,7 +57,7 @@
         categories.add(ThreadDao.THREAD_HARVESTING_STATUS.getName());
         categories.add(ThreadDao.THREAD_HEADER.getName());
         categories.add(ThreadDao.THREAD_STATE.getName());
-        categories.add(ThreadDao.THREAD_SUMMARY.getName());
+        categories.add(ThreadDaoCategories.THREAD_SUMMARY.getName());
         categories.add(ThreadDao.THREAD_CONTENTION_SAMPLE.getName());
         return categories;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategories.java	Tue Nov 18 16:02:57 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;
+
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.thread.model.ThreadSummary;
+import java.util.Arrays;
+
+/**
+ *
+ */
+public class ThreadDaoCategories {
+
+    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));
+}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Tue Nov 18 16:02:57 2014 +0100
@@ -49,13 +49,15 @@
 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.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadContentionSample;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
 import com.redhat.thermostat.thread.model.ThreadHeader;
 import com.redhat.thermostat.thread.model.ThreadState;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 import com.redhat.thermostat.thread.model.VmDeadLockData;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -65,20 +67,11 @@
 public class ThreadDaoImpl implements ThreadDao {
     
     private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class);
-    
+
+    static final SummaryDescriptor SUMMARY = new SummaryDescriptorBuilder().build();
+
     // Queries
 
-    static final String QUERY_LATEST_SUMMARY = "QUERY "
-            + THREAD_SUMMARY.getName() + " WHERE '"
-            + Key.AGENT_ID.getName() + "' = ?s AND '" 
-            + Key.VM_ID.getName() + "' = ?s SORT '" 
-            + Key.TIMESTAMP.getName() + "' DSC LIMIT 1";
-    static final String QUERY_SUMMARY_SINCE = "QUERY "
-            + THREAD_SUMMARY.getName() + " WHERE '"
-            + Key.AGENT_ID.getName() + "' = ?s AND '" 
-            + Key.VM_ID.getName() + "' = ?s AND '"
-            + Key.TIMESTAMP.getName() + "' > ?l SORT '"
-            + Key.TIMESTAMP.getName() + "' DSC";
     static final String QUERY_LATEST_HARVESTING_STATUS = "QUERY "
             + THREAD_HARVESTING_STATUS.getName() + " WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s AND '" 
@@ -135,18 +128,7 @@
             + THREAD_PROBE_START.getName() + "' ASC";
 
     // Data modifying descriptors
-    
-    // ADD vm-thread-summary SET 'agentId' = ?s , \
-    //                           'vmId' = ?s , \
-    //                           'currentLiveThreads' = ?l , \
-    //                           'currentDaemonThreads' = ?l , \
-    //                           'timeStamp' = ?l
-    static final String DESC_ADD_THREAD_SUMMARY = "ADD " + THREAD_SUMMARY.getName() +
-            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
-                 "'" + Key.VM_ID.getName() + "' = ?s , " +
-                 "'" + LIVE_THREADS_KEY.getName() + "' = ?l , " +
-                 "'" + DAEMON_THREADS_KEY.getName() + "' = ?l , " +
-                 "'" + Key.TIMESTAMP.getName() + "' = ?l";
+
     // ADD vm-thread-harvesting SET 'agentId' = ?s , \
     //                              'vmId' = ?s , \
     //                              'timeStamp' = ?l , \
@@ -211,7 +193,9 @@
     
     public ThreadDaoImpl(Storage storage) {
         this.storage = storage;
-        storage.registerCategory(THREAD_SUMMARY);
+
+        storage.registerCategory(SUMMARY.getCategory());
+
         storage.registerCategory(THREAD_HARVESTING_STATUS);
         storage.registerCategory(THREAD_HEADER);
         storage.registerCategory(THREAD_STATE);
@@ -219,7 +203,7 @@
 
         storage.registerCategory(DEADLOCK_INFO);
     }
-    
+
     @Override
     public List<ThreadHeader> getThreads(VmRef ref) {
         
@@ -469,41 +453,43 @@
 
     @Override
     public void saveSummary(ThreadSummary summary) {
-        StatementDescriptor<ThreadSummary> desc = new StatementDescriptor<>(THREAD_SUMMARY, DESC_ADD_THREAD_SUMMARY);
-        PreparedStatement<ThreadSummary> prepared;
+
         try {
-            prepared = storage.prepareStatement(desc);
-            prepared.setString(0, summary.getAgentId());
-            prepared.setString(1, summary.getVmId());
-            prepared.setLong(2, summary.getCurrentLiveThreads());
-            prepared.setLong(3, summary.getCurrentDaemonThreads());
-            prepared.setLong(4, summary.getTimeStamp());
-            prepared.execute();
-        } catch (DescriptorParsingException e) {
-            logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
-        } catch (StatementExecutionException e) {
-            logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e);
-        }
+            SUMMARY.statementAdd(summary, storage);
+
+        } catch (Exception ignore) { ignore.printStackTrace(); }
     }
-    
+
     @Override
-    public ThreadSummary loadLastestSummary(VmRef ref) {
-        PreparedStatement<ThreadSummary> stmt = prepareQuery(THREAD_SUMMARY, QUERY_LATEST_SUMMARY, ref);
-        if (stmt == null) {
-            return null;
-        }
-        
-        return getFirstResult(stmt);
+    public List<ThreadSummary> getSummary(VmRef ref, SessionID session, Range<Long> range, int limit) {
+
+        List<ThreadSummary> result = new ArrayList<>();
+        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(); }
+
+        return result;
     }
-    
+
     @Override
-    public List<ThreadSummary> loadSummary(VmRef ref, long since) {
-        PreparedStatement<ThreadSummary> stmt = prepareQuery(THREAD_SUMMARY, QUERY_SUMMARY_SINCE, ref, since, null);
-        if (stmt == null) {
-            return Collections.emptyList();
-        }
+    public List<SessionID> getAvailableThreadSummarySessions(VmRef ref, Range<Long> range, int limit) {
+        List<SessionID> result = new ArrayList<>();
+
+        Cursor<ThreadSummary> cursor = null;
 
-        return getAllResults(stmt);
+        try {
+            cursor = SUMMARY.queryGet(ref, range, limit, storage);
+            while (cursor.hasNext()) {
+                ThreadSummary summary = cursor.next();
+                result.add(new SessionID(summary.getSession()));
+            }
+        } catch (Exception ignore) { ignore.printStackTrace(); }
+
+        return result;
     }
 
     @Override
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java	Tue Nov 18 16:02:57 2014 +0100
@@ -58,11 +58,11 @@
         descs = new HashSet<>();
         descs.add(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO);
         descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS);
-        descs.add(ThreadDaoImpl.QUERY_LATEST_SUMMARY);
-        descs.add(ThreadDaoImpl.QUERY_SUMMARY_SINCE);
+
+        descs.addAll(ThreadDaoImpl.SUMMARY.describe());
+
         descs.add(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA);
         descs.add(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS);
-        descs.add(ThreadDaoImpl.DESC_ADD_THREAD_SUMMARY);
 
         descs.add(ThreadDaoImpl.ADD_THREAD_HEADER);
         descs.add(ThreadDaoImpl.QUERY_THREAD_HEADER);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoKeys.java	Tue Nov 18 16:02:57 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;
+
+import com.redhat.thermostat.storage.core.Key;
+
+/**
+ *
+ */
+public class ThreadDaoKeys {
+    public static final Key<String> SESSION = new Key<>("session");
+
+    public static final Key<Long> LIVE_THREADS_KEY = new Key<Long>("currentLiveThreads");
+    public static final Key<Long> DAEMON_THREADS_KEY = new Key<Long>("currentDaemonThreads");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/Descriptor.java	Tue Nov 18 16:02:57 2014 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/DescriptorBuilder.java	Tue Nov 18 16:02:57 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.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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptor.java	Tue Nov 18 16:02:57 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.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;
+
+    protected String sessionsDesc;
+
+    public Set<String> describe() {
+        Set<String> description = new HashSet<>();
+
+        description.add(rangeDesc);
+        description.add(addDesc);
+        description.add(sessionsDesc);
+
+        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 Cursor<ThreadSummary> queryGet(VmRef ref, Range<Long> range,
+                                          int limit, Storage storage)
+            throws DescriptorParsingException, StatementExecutionException
+    {
+        // "QUERY vm-thread-summary WHERE 'vmId' = ?s , 'timeStamp' >= ?l
+        //  AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i";
+
+        StatementDescriptor<ThreadSummary> desc = null;
+        try {
+            desc = new StatementDescriptor<>(getCategory(), sessionsDesc);
+            PreparedStatement<ThreadSummary> 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(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;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorBuilder.java	Tue Nov 18 16:02:57 2014 +0100
@@ -0,0 +1,96 @@
+/*
+ * 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 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.sessionsDesc = querySessions.toString();
+
+        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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/SessionID.java	Tue Nov 18 16:02:57 2014 +0100
@@ -0,0 +1,77 @@
+/*
+ * 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.model;
+
+import java.util.UUID;
+
+/**
+ *
+ */
+public class SessionID  {
+
+    private String id;
+
+    public SessionID() {
+        id = UUID.randomUUID().toString();
+    }
+
+    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;
+    }
+}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadPojo.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadPojo.java	Tue Nov 18 16:02:57 2014 +0100
@@ -45,6 +45,7 @@
 
     private ThreadHeader header;
     private String referenceID;
+    private String sessionID;
 
     private String vmId;
 
@@ -88,6 +89,15 @@
         return referenceID;
     }
 
+    @Persist
+    public void setSessionID(String sessionID) {
+        this.sessionID = sessionID;
+    }
+
+    public String getSessionID() {
+        return sessionID;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -98,6 +108,8 @@
 
         if (header != null ? !header.equals(that.header) : that.header != null)
             return false;
+        if (sessionID != null ? !sessionID.equals(that.sessionID) : that.sessionID != null)
+            return false;
 
         return true;
     }
@@ -106,6 +118,7 @@
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + (header != null ? header.hashCode() : 0);
+        result = 31 * result + (sessionID != null ? sessionID.hashCode() : 0);
         return result;
     }
 }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Tue Nov 18 16:02:57 2014 +0100
@@ -51,6 +51,8 @@
     
     private long timestamp;
 
+    private String session;
+
     public ThreadSummary() {
         this(null);
     }
@@ -98,11 +100,21 @@
     public void setTimeStamp(long timestamp) {
         this.timestamp = timestamp;
     }
-    
+
     @Override
     public String toString() {
         return "[timestamp: " + timestamp + ", currentLiveThreads: " +
                currentLiveThreads + ", daemonThreads: " + daemonThreads + "]";
     }
+
+    @Persist
+    public void setSession(String session) {
+        this.session = session;
+    }
+
+    @Persist
+    public String getSession() {
+        return session;
+    }
 }
 
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistrationTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistrationTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -63,7 +63,7 @@
         assertTrue(categories.contains(ThreadDao.DEADLOCK_INFO.getName()));
         assertTrue(categories.contains(ThreadDao.THREAD_HEADER.getName()));
         assertTrue(categories.contains(ThreadDao.THREAD_STATE.getName()));
-        assertTrue(categories.contains(ThreadDao.THREAD_SUMMARY.getName()));
+        assertTrue(categories.contains(ThreadDaoCategories.THREAD_SUMMARY.getName()));
         assertTrue(categories.contains(ThreadDao.THREAD_HARVESTING_STATUS.getName()));
         assertTrue(categories.contains(ThreadDao.THREAD_CONTENTION_SAMPLE.getName()));
     }
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -146,16 +146,7 @@
         DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS, triple.third);
         assertThreadMetadata(triple, data);
     }
-    
-    @Test
-    public void canGetMetadataForLatestSummaryQuery() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest(); 
-        
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_SUMMARY, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-    
+
     @Test
     public void canGetMetadataForThreadHeader() {
         Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
@@ -213,15 +204,7 @@
         assertNull(data.getVmId());
     }
 
-    @Test
-    public void canGetMetadataQuerySummarySince() {
-        Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
 
-        StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration();
-        DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_SUMMARY_SINCE, triple.third);
-        assertThreadMetadata(triple, data);
-    }
-    
     @Test
     public void canGetMetadataOldestThreadState() {
         Triple<String, String, PreparedParameter[]> triple = setupForMetaDataTest();
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -89,12 +89,6 @@
     @Test
     public void preparedQueryDescriptorsAreSane() {
 
-        String expectedQueryLatestSummary = "QUERY vm-thread-summary WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
-        assertEquals(expectedQueryLatestSummary, ThreadDaoImpl.QUERY_LATEST_SUMMARY);
-
-        String expectedQuerySummarySince = "QUERY vm-thread-summary WHERE 'agentId' = ?s AND 'vmId' = ?s AND 'timeStamp' > ?l SORT 'timeStamp' DSC";
-        assertEquals(expectedQuerySummarySince, ThreadDaoImpl.QUERY_SUMMARY_SINCE);
-
         String expectedQueryLatestHarvestingStatus = "QUERY vm-thread-harvesting WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
         assertEquals(expectedQueryLatestHarvestingStatus, ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS);
 
@@ -113,13 +107,6 @@
         String expectedQueryThreadLatestDeadlockInfo = "QUERY vm-deadlock-data WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
         assertEquals(expectedQueryThreadLatestDeadlockInfo, ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO);
 
-        String addThreadSummary = "ADD vm-thread-summary SET 'agentId' = ?s , " +
-                                            "'vmId' = ?s , " +
-                                            "'currentLiveThreads' = ?l , " +
-                                            "'currentDaemonThreads' = ?l , " +
-                                            "'timeStamp' = ?l";
-        assertEquals(addThreadSummary, ThreadDaoImpl.DESC_ADD_THREAD_SUMMARY);
-
         String addThreadHarvesting = "ADD vm-thread-harvesting SET 'agentId' = ?s , " +
                                                     "'vmId' = ?s , " +
                                                     "'timeStamp' = ?l , " +
@@ -176,7 +163,7 @@
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         
         verify(storage).registerCategory(ThreadDao.THREAD_HARVESTING_STATUS);
-        verify(storage).registerCategory(ThreadDao.THREAD_SUMMARY);
+        verify(storage).registerCategory(ThreadDaoCategories.THREAD_SUMMARY);
     }
 
     @SuppressWarnings("unchecked")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/descriptor/SummaryDescriptorBuilderTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -0,0 +1,90 @@
+/*
+ * 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.StatementDescriptor;
+import com.redhat.thermostat.storage.testutils.StatementDescriptorTester;
+import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories;
+import com.redhat.thermostat.thread.model.ThreadSummary;
+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();
+        testStatement(summary.addDesc);
+    }
+
+    @Test
+    public void testRangeDesc() throws Exception {
+
+        SummaryDescriptor summary = new SummaryDescriptorBuilder().build();
+        testStatement(summary.rangeDesc);
+    }
+
+    @Test
+    public void testSessionDesc() throws Exception {
+
+        SummaryDescriptor summary = new SummaryDescriptorBuilder().build();
+        testStatement(summary.sessionsDesc);
+    }
+
+    private void testStatement(String statement) throws Exception {
+
+        StatementDescriptorTester<ThreadSummary> tester = new StatementDescriptorTester<>();
+        StatementDescriptor<ThreadSummary> desc =
+                new StatementDescriptor<>(ThreadDaoCategories.THREAD_SUMMARY, 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/descriptor/SummaryDescriptorTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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 testGetSessionsRange() throws Exception {
+
+        String expected =
+                "QUERY vm-thread-summary WHERE 'vmId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i";
+        assertEquals(expected, descriptor.sessionsDesc);
+
+    }
+
+    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/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java	Tue Nov 18 16:02:57 2014 +0100
@@ -42,6 +42,7 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import java.lang.management.ManagementFactory;
 import java.lang.management.ThreadMXBean;
 import java.util.concurrent.ScheduledExecutorService;
@@ -102,7 +103,7 @@
             return false;
         }
 
-        harvester = threadPool.scheduleAtFixedRate(new HarvesterAction(),
+        harvester = threadPool.scheduleAtFixedRate(new HarvesterAction(true),
                                                    DEFAULT_INITIAL_DELAY,
                                                    DEFAULT_PERIOD,
                                                    DEFAULT_TIME_UNIT);
@@ -195,6 +196,14 @@
     }
 
     private class HarvesterAction implements Runnable {
+
+        private boolean newSession;
+        private SessionID sessionID;
+
+        private HarvesterAction(boolean newSession) {
+            this.newSession = newSession;
+        }
+
         @Override
         public void run() {
             if (collectorBean == null) {
@@ -220,7 +229,13 @@
                     }
                 } catch (UnsupportedOperationException ignore) {}
 
-                harvesterHelper.collectAndSaveThreadData(collectorBean);
+                if (newSession) {
+                    sessionID = new SessionID();
+                    newSession = false;
+                }
+
+                harvesterHelper.collectAndSaveThreadData(sessionID, collectorBean);
+
             } else {
                 logger.log(Level.WARNING, "ThreadMXBean is null, is JMX available?");
             }
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/HarvesterHelper.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/HarvesterHelper.java	Tue Nov 18 16:02:57 2014 +0100
@@ -41,6 +41,7 @@
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadContentionSample;
 import com.redhat.thermostat.thread.model.ThreadHeader;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadState;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 import java.lang.management.ThreadInfo;
@@ -83,11 +84,14 @@
         this.contentionHelper = contentionHelper;
     }
 
-    synchronized void collectAndSaveThreadData(ThreadMXBean collectorBean) {
+    synchronized void collectAndSaveThreadData(SessionID session,
+                                               ThreadMXBean collectorBean)
+    {
         long timestamp = clock.getRealTimeMillis();
 
         ThreadSummary summary = summaryHelper.createThreadSummary(collectorBean,
-                                                                  timestamp);
+                                                                  timestamp,
+                                                                  session);
         summaryHelper.saveSummary(summary);
 
         // this two can't be null, but the check is there to allow for
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadStateHelper.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadStateHelper.java	Tue Nov 18 16:02:57 2014 +0100
@@ -54,7 +54,8 @@
         this.vmId = vmId;
         this.threadDao = threadDao;
     }
-
+iqQ:q!
+    
     public ThreadState createThreadState(ThreadHeader header, ThreadInfo beanInfo,
                                          long timestamp)
     {
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadSummaryHelper.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadSummaryHelper.java	Tue Nov 18 16:02:57 2014 +0100
@@ -38,6 +38,7 @@
 
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 
 import java.lang.management.ThreadMXBean;
@@ -56,7 +57,7 @@
         this.threadDao = threadDao;
     }
 
-    ThreadSummary createThreadSummary(ThreadMXBean collectorBean, long timestamp) {
+    ThreadSummary createThreadSummary(ThreadMXBean collectorBean, long timestamp, SessionID session) {
 
         String wId = writerId.getWriterID();
 
@@ -67,6 +68,8 @@
         summary.setTimeStamp(timestamp);
         summary.setVmId(vmId);
 
+        summary.setSession(session.getId());
+
         return summary;
     }
 
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterHelperTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterHelperTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -38,15 +38,15 @@
 
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadHeader;
 import com.redhat.thermostat.thread.model.ThreadState;
 import com.redhat.thermostat.thread.model.ThreadSummary;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -71,7 +71,7 @@
     private ThreadContentionHelper contentionHelper;
 
     private ThreadMXBean collectorBean;
-
+    private SessionID sessionID;
     @Before
     public void setUp() {
         summaryHelper = mock(ThreadSummaryHelper.class);
@@ -87,6 +87,8 @@
         when(clock.getRealTimeMillis()).thenReturn(DEFAULT_TIMESTAMP);
 
         vmId = "42";
+
+        sessionID = new SessionID("0xcafe");
     }
 
     @Test
@@ -94,7 +96,8 @@
 
         ThreadSummary summary = mock(ThreadSummary.class);
         when(summaryHelper.createThreadSummary(collectorBean,
-                                               DEFAULT_TIMESTAMP)).
+                                               DEFAULT_TIMESTAMP,
+                                               sessionID)).
             thenReturn(summary);
 
         HarvesterHelper harvester = new HarvesterHelper(threadDao, clock, vmId,
@@ -102,11 +105,12 @@
                                                         headerHelper,
                                                         stateHelper,
                                                         contentionHelper);
-        harvester.collectAndSaveThreadData(collectorBean);
+        harvester.collectAndSaveThreadData(sessionID, collectorBean);
 
         verify(clock).getRealTimeMillis();
         verify(summaryHelper).createThreadSummary(collectorBean,
-                                                  DEFAULT_TIMESTAMP);
+                                                  DEFAULT_TIMESTAMP,
+                                                  sessionID);
         verify(summaryHelper).saveSummary(summary);
     }
 
@@ -121,7 +125,7 @@
                                                         headerHelper,
                                                         stateHelper,
                                                         contentionHelper);
-        harvester.collectAndSaveThreadData(collectorBean);
+        harvester.collectAndSaveThreadData(sessionID, collectorBean);
         verify(collectorBean).getAllThreadIds();
 
         verify(collectorBean).getThreadInfo(ids, true, true);
@@ -164,7 +168,7 @@
                                                         headerHelper,
                                                         stateHelper,
                                                         contentionHelper);
-        harvester.collectAndSaveThreadData(collectorBean);
+        harvester.collectAndSaveThreadData(sessionID, collectorBean);
 
         verify(headerHelper, times(2)).checkAndSaveThreadHeader(header1);
         verify(headerHelper).checkAndSaveThreadHeader(header2);
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -40,6 +40,7 @@
 import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -56,6 +57,7 @@
 import static junit.framework.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -101,7 +103,6 @@
             thenReturn(null);
 
         HarvesterHelper helper = mock(HarvesterHelper.class);
-
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper);
 
@@ -125,7 +126,6 @@
         // Mostly the same as testStart, but we call harvester.start() twice
 
         HarvesterHelper helper = mock(HarvesterHelper.class);
-
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper);
 
@@ -150,7 +150,6 @@
             thenReturn(future);
 
         HarvesterHelper helper = mock(HarvesterHelper.class);
-
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper);
 
@@ -174,7 +173,6 @@
             thenReturn(future);
 
         HarvesterHelper helper = mock(HarvesterHelper.class);
-
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper);
 
@@ -200,7 +198,6 @@
             thenReturn(future);
 
         HarvesterHelper helper = mock(HarvesterHelper.class);
-
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper);
 
@@ -234,7 +231,6 @@
 
 
         HarvesterHelper helper = mock(HarvesterHelper.class);
-
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper);
 
@@ -245,7 +241,7 @@
 
         harvesterRunnable.run();
 
-        verify(helper).collectAndSaveThreadData(sunBean);
+        verify(helper).collectAndSaveThreadData(any(SessionID.class), eq(sunBean));
     }
 
     @Test
@@ -281,7 +277,7 @@
 
         harvesterRunnable.run();
 
-        verify(helper).collectAndSaveThreadData(mxBean);
+        verify(helper).collectAndSaveThreadData(any(SessionID.class), eq(mxBean));
     }
 
     @Test
@@ -289,6 +285,7 @@
 
         final ThreadMXBean mxBean = mock(ThreadMXBean.class);
         HarvesterHelper helper = mock(HarvesterHelper.class);
+
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper)
         {
@@ -313,6 +310,7 @@
 
         final ThreadMXBean mxBean = mock(ThreadMXBean.class);
         HarvesterHelper helper = mock(HarvesterHelper.class);
+
         Harvester harvester = new Harvester(pid, executor, pool, helper,
                                             deadlockHelper)
         {
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadHarvesterTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadHarvesterTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -118,7 +118,7 @@
     public void testStop() {
         ThreadDao dao = mock(ThreadDao.class);
         Request request = mock(Request.class);
-        
+
         final Harvester harverster = mock(Harvester.class);
         
         ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadSummaryHelperTest.java	Wed Nov 05 16:55:16 2014 +0100
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadSummaryHelperTest.java	Tue Nov 18 16:02:57 2014 +0100
@@ -38,12 +38,12 @@
 
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.SessionID;
 import com.redhat.thermostat.thread.model.ThreadSummary;
+import java.lang.management.ThreadMXBean;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.lang.management.ThreadMXBean;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
@@ -64,6 +64,8 @@
 
     private ThreadMXBean collectorBean;
 
+    private SessionID sessionID;
+
     @Before
     public void setUp() throws Exception {
         vmId = "testVM";
@@ -75,6 +77,8 @@
         collectorBean = mock(ThreadMXBean.class);
         when(collectorBean.getThreadCount()).thenReturn(DEFAULT_THREAD_COUNT);
         when(collectorBean.getDaemonThreadCount()).thenReturn(DEFAULT_DAEMON_THREAD_COUNT);
+
+        sessionID = new SessionID("0xcafe");
     }
 
     @Test
@@ -84,7 +88,7 @@
 
         long timestamp = -1l;
 
-        ThreadSummary summary = helper.createThreadSummary(collectorBean, timestamp);
+        ThreadSummary summary = helper.createThreadSummary(collectorBean, timestamp, sessionID);
 
         assertNotNull(summary);
 
@@ -95,6 +99,8 @@
         assertEquals(summary.getAgentId(), DEFAULT_W_ID);
         assertEquals(summary.getVmId(), vmId);
 
+        assertEquals(summary.getSession(), sessionID.getId());
+
         assertEquals(summary.getCurrentLiveThreads(), DEFAULT_THREAD_COUNT);
         assertEquals(summary.getCurrentDaemonThreads(), DEFAULT_DAEMON_THREAD_COUNT);
         assertEquals(summary.getTimeStamp(), timestamp);