changeset 1249:ec60b0403fb0

Use WriterID service over Storage.get/setAgentId() (Part 4). Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-September/008100.html PR1509
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 02 Sep 2013 11:34:12 +0200
parents 84ea87a65eda
children 3a639bf4c6ce
files thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInfoHelperTest.java thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineControllerTest.java thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/VmDeadLockControllerTest.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadHarvestingStatus.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/VmDeadLockData.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/model/ThreadModelPojosTest.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadHarvester.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.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
diffstat 16 files changed, 221 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInfoHelperTest.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInfoHelperTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -50,22 +50,22 @@
 
     @Test
     public void verifyMap() {
-        ThreadInfoData data1 = new ThreadInfoData();
+        ThreadInfoData data1 = new ThreadInfoData("foo-agent");
         data1.setThreadName("test1");
         data1.setThreadId(1);
         data1.setState(Thread.State.RUNNABLE);
         
-        ThreadInfoData data2 = new ThreadInfoData();
+        ThreadInfoData data2 = new ThreadInfoData("foo-agent");
         data2.setThreadName("test2");
         data2.setThreadId(2);
         data2.setState(Thread.State.BLOCKED);
         
-        ThreadInfoData data3 = new ThreadInfoData();
+        ThreadInfoData data3 = new ThreadInfoData("foo-agent");
         data3.setThreadName("test1");
         data3.setThreadId(1);
         data3.setState(Thread.State.TIMED_WAITING);
         
-        ThreadInfoData data4 = new ThreadInfoData();
+        ThreadInfoData data4 = new ThreadInfoData("foo-agent");
         data4.setThreadName("test2");
         data4.setThreadId(2);
         data4.setState(Thread.State.RUNNABLE);
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineControllerTest.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineControllerTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -94,31 +94,31 @@
     @Test
     public void testDisplayStats() {
         
-        ThreadInfoData data1 = new ThreadInfoData();
+        ThreadInfoData data1 = new ThreadInfoData("foo-agent");
         data1.setThreadName("test1");
         data1.setThreadId(1);
         data1.setState(Thread.State.RUNNABLE);
         data1.setTimeStamp(100);
         
-        ThreadInfoData data2 = new ThreadInfoData();
+        ThreadInfoData data2 = new ThreadInfoData("foo-agent");
         data2.setThreadName("test2");
         data2.setThreadId(2);
         data2.setTimeStamp(1000);
         data2.setState(Thread.State.BLOCKED);
         
-        ThreadInfoData data3 = new ThreadInfoData();
+        ThreadInfoData data3 = new ThreadInfoData("foo-agent");
         data3.setThreadName("test1");
         data3.setThreadId(1);
         data3.setState(Thread.State.TIMED_WAITING);
         data3.setTimeStamp(200);
         
-        ThreadInfoData data4 = new ThreadInfoData();
+        ThreadInfoData data4 = new ThreadInfoData("foo-agent");
         data4.setThreadName("test2");
         data4.setThreadId(2);
         data4.setState(Thread.State.BLOCKED);
         data4.setTimeStamp(2000);
         
-        ThreadInfoData data5 = new ThreadInfoData();
+        ThreadInfoData data5 = new ThreadInfoData("foo-agent");
         data5.setThreadName("test2");
         data5.setThreadId(2);
         data5.setState(Thread.State.RUNNABLE);
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/VmDeadLockControllerTest.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/VmDeadLockControllerTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -88,7 +88,7 @@
     @Test
     public void verifyRealDeadLockDataIsDisplayedOnViewAction() {
         final String DESCRIPTION = "foo bar";
-        VmDeadLockData data = new VmDeadLockData();
+        VmDeadLockData data = new VmDeadLockData("foo-agent");
         data.setDeadLockDescription(DESCRIPTION);
 
         controller.initialize();
@@ -108,7 +108,7 @@
 
     @Test
     public void verifyNoDeadLockDataIsDisplayedOnViewAction() {
-        VmDeadLockData data = new VmDeadLockData();
+        VmDeadLockData data = new VmDeadLockData("foo-agent");
         data.setDeadLockDescription(VmDeadLockData.NO_DEADLOCK);
 
         controller.initialize();
@@ -160,7 +160,7 @@
     public void verifyTimerActionRefreshesView() {
         doThrow(new AssertionError()).when(collector).requestDeadLockCheck();
 
-        VmDeadLockData data = new VmDeadLockData();
+        VmDeadLockData data = new VmDeadLockData("foo-agent");
         data.setDeadLockDescription(VmDeadLockData.NO_DEADLOCK);
         controller.initialize();
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Mon Sep 02 11:34:12 2013 +0200
@@ -142,9 +142,6 @@
         Replace<VMThreadCapabilities> replace = storage.createReplace(THREAD_CAPABILITIES);
         ExpressionFactory factory = new ExpressionFactory();
         String agentId = caps.getAgentId();
-        if (agentId == null) {
-            agentId = storage.getAgentId();
-        }
         Expression agentKey = factory.equalTo(Key.AGENT_ID, agentId);
         Expression vmKey = factory.equalTo(Key.VM_ID, caps.getVmId());
         Expression and = factory.and(agentKey, vmKey);
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadHarvestingStatus.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadHarvestingStatus.java	Mon Sep 02 11:34:12 2013 +0200
@@ -46,6 +46,14 @@
     private String vmId;
     private long timeStamp;
     private boolean collecting;
+    
+    public ThreadHarvestingStatus() {
+        this(null);
+    }
+    
+    public ThreadHarvestingStatus(String writerId) {
+        super(writerId);
+    }
 
     @Persist
     public String getVmId() {
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java	Mon Sep 02 11:34:12 2013 +0200
@@ -61,7 +61,15 @@
     private long waitedCount;
     
     private long timestamp;
+    
+    public ThreadInfoData() {
+        this(null);
+    }
 
+    public ThreadInfoData(String writerId) {
+        super(writerId);
+    }
+    
     public void setStackTrace(StackTraceElement[] stackTrace) {
         this.stackTrace = stackTrace;
     }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Mon Sep 02 11:34:12 2013 +0200
@@ -51,6 +51,14 @@
     
     private long timestamp;
 
+    public ThreadSummary() {
+        this(null);
+    }
+    
+    public ThreadSummary(String writerId) {
+        super(writerId);
+    }
+    
     @Persist
     public void setVmId(String vmId) {
         this.vmId = vmId;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java	Mon Sep 02 11:34:12 2013 +0200
@@ -45,9 +45,16 @@
 public class VMThreadCapabilities extends BasePojo {
     
     private String[] features;
+    private String vmId;
+    
+    public VMThreadCapabilities() {
+        this(null);
+    }
 
-    private String vmId;
-
+    public VMThreadCapabilities(String writerId) {
+        super(writerId);
+    }
+    
     @Persist
     public void setVmId(String vmId) {
         this.vmId = vmId;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VmDeadLockData.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VmDeadLockData.java	Mon Sep 02 11:34:12 2013 +0200
@@ -50,6 +50,14 @@
     private long timeStamp;
     private String vmId;
     private String description;
+    
+    public VmDeadLockData() {
+        this(null);
+    }
+    
+    public VmDeadLockData(String writerId) {
+        super(writerId);
+    }
 
     @Persist
     @Override
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -40,7 +40,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertNull;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -111,12 +110,13 @@
         VmRef ref = mock(VmRef.class);
         when(ref.getVmId()).thenReturn("VM42");
         
+        String agentId = "0xcafe";
         HostRef agent = mock(HostRef.class);
-        when(agent.getAgentId()).thenReturn("0xcafe");
+        when(agent.getAgentId()).thenReturn(agentId);
         
         when(ref.getHostRef()).thenReturn(agent);
 
-        VMThreadCapabilities expected = new VMThreadCapabilities();
+        VMThreadCapabilities expected = new VMThreadCapabilities(agentId);
         expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY });
         @SuppressWarnings("unchecked")
         Cursor<VMThreadCapabilities> cursor = (Cursor<VMThreadCapabilities>) mock(Cursor.class);
@@ -152,12 +152,13 @@
         VmRef ref = mock(VmRef.class);
         when(ref.getVmId()).thenReturn("VM42");
 
+        String agentId = "0xcafe";
         HostRef agent = mock(HostRef.class);
-        when(agent.getAgentId()).thenReturn("0xcafe");
+        when(agent.getAgentId()).thenReturn(agentId);
 
         when(ref.getHostRef()).thenReturn(agent);
 
-        VMThreadCapabilities expected = new VMThreadCapabilities();
+        VMThreadCapabilities expected = new VMThreadCapabilities(agentId);
         expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY });
         @SuppressWarnings("unchecked")
         Cursor<VMThreadCapabilities> cursor = (Cursor<VMThreadCapabilities>) mock(Cursor.class);
@@ -179,36 +180,19 @@
 
     /*
      * Tests saving of VMCapabilities when agentId has been explicitly set
-     * in thread capabilities model class.
+     * in thread capabilities model class. Every model class is required
+     * to set this explicitly.
      */
     @Test
     public void testSaveVMCapabilities() {
         String agentId = "fooAgent";
-        doTestSaveVMCaps(false, agentId);
-    }
-    
-    /*
-     * Tests saving of VMCapabilities when agentId has NOT been explicitly set
-     * in thread capabilities model class. AgentId should get filled in from
-     * storage.
-     */
-    @Test
-    public void testSaveVMCapabilitiesWithNoAgentIdExplicitlySet() {
-        String agentId = "fooStorageAgent";
-        doTestSaveVMCaps(true, agentId);
-    }
-    
-    private void doTestSaveVMCaps(boolean agentIdFromStorage, String agentId) {
         Storage storage = mock(Storage.class);
         @SuppressWarnings("unchecked")
         Replace<VMThreadCapabilities> replace = mock(Replace.class);
         when(storage.createReplace(eq(ThreadDao.THREAD_CAPABILITIES))).thenReturn(replace);
-        if (agentIdFromStorage) {
-            when(storage.getAgentId()).thenReturn(agentId);
-        }
         
         String vmId = "VM42";
-        VMThreadCapabilities caps = new VMThreadCapabilities();
+        VMThreadCapabilities caps = new VMThreadCapabilities(agentId);
         String[] capsFeatures = new String[] {
                 ThreadDao.CONTENTION_MONITOR,
                 ThreadDao.CPU_TIME,
@@ -219,12 +203,6 @@
         assertTrue(caps.supportCPUTime());
         assertTrue(caps.supportThreadAllocatedMemory());
         caps.setVmId(vmId);
-        if (!agentIdFromStorage) {
-            caps.setAgentId(agentId);
-        } else {
-            // case where we want to have agentId null on caps itself.
-            assertNull(caps.getAgentId());
-        }
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         dao.saveCapabilities(caps);
         
@@ -237,6 +215,7 @@
         verify(replace).setPojo(caps);
         verify(replace).where(expected);
         verify(replace).apply();
+        assertEquals(agentId, caps.getAgentId());
     }
 
     @Test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/model/ThreadModelPojosTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.model;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.Test;
+
+public class ThreadModelPojosTest {
+
+    private static final Class<?>[] CLASSES_LIST = new Class[] {
+        ThreadHarvestingStatus.class,
+        ThreadInfoData.class,
+        ThreadSummary.class,
+        VmDeadLockData.class,
+        VMThreadCapabilities.class
+    };
+
+    @Test
+    public void testBasicInstantiation() {
+        ArrayList<Class<?>> failureClasses = new ArrayList<>();
+        for (Class<?> clazz : CLASSES_LIST) {
+            try {
+                // pojo converters use this
+                clazz.newInstance();
+                // pass
+            } catch (InstantiationException | IllegalAccessException e) {
+                failureClasses.add(clazz);
+            }
+        }
+        String msg = "Should be able to instantiate class using no-arg constructor: "
+                + failureClasses;
+        assertEquals(msg, 0, failureClasses.size());
+    }
+}
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java	Mon Sep 02 11:34:12 2013 +0200
@@ -52,6 +52,7 @@
 import com.redhat.thermostat.common.Clock;
 import com.redhat.thermostat.common.SystemClock;
 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.ThreadInfoData;
 import com.redhat.thermostat.thread.model.ThreadSummary;
@@ -65,29 +66,35 @@
     
     private static final Logger logger = LoggingUtils.getLogger(Harvester.class);
     
+    private final ScheduledExecutorService threadPool;
+    private final Clock clock;
+    
+    private final MXBeanConnectionPool connectionPool;
+    private final ThreadDao threadDao;
+    private final String vmId;
+    private final int pid;
+    private final WriterID writerId;
     private boolean isConnected;
-    private ScheduledExecutorService threadPool;
     private ScheduledFuture<?> harvester;
-    private Clock clock;
-    
-    private MXBeanConnectionPool connectionPool;
     private MXBeanConnection connection;
     private ThreadMXBean collectorBean;
-    private ThreadDao threadDao;
-    private String vmId;
-    private int pid;
     
-    Harvester(ThreadDao threadDao, ScheduledExecutorService threadPool, String vmId, int pid, MXBeanConnectionPool connectionPool) {
-        this(threadDao, threadPool, new SystemClock(), vmId, pid, connectionPool);
+    Harvester(ThreadDao threadDao, ScheduledExecutorService threadPool,
+            String vmId, int pid, MXBeanConnectionPool connectionPool,
+            WriterID writerId) {
+        this(threadDao, threadPool, new SystemClock(), vmId, pid, connectionPool, writerId);
     }
 
-    Harvester(ThreadDao threadDao, ScheduledExecutorService threadPool, Clock clock, String vmId, int pid, MXBeanConnectionPool connectionPool) {
+    Harvester(ThreadDao threadDao, ScheduledExecutorService threadPool,
+            Clock clock, String vmId, int pid,
+            MXBeanConnectionPool connectionPool, WriterID writerId) {
         this.threadDao = threadDao;
         this.vmId = vmId;
         this.pid = pid;
         this.threadPool = threadPool;
         this.connectionPool = connectionPool;
         this.clock = clock;
+        this.writerId = writerId;
     }
     
     synchronized boolean start() {
@@ -170,8 +177,9 @@
     synchronized void harvestData() {
       try {
           long timestamp = clock.getRealTimeMillis();
-          
-          ThreadSummary summary = new ThreadSummary();
+
+          String wId = writerId.getWriterID();
+          ThreadSummary summary = new ThreadSummary(wId);
           
           if (collectorBean == null) {
               collectorBean = getDataCollectorBean(connection);
@@ -203,7 +211,7 @@
           ThreadInfo[] threadInfos = collectorBean.getThreadInfo(ids, true, true);
           
           for (int i = 0; i < ids.length; i++) {
-              ThreadInfoData info = new ThreadInfoData();
+              ThreadInfoData info = new ThreadInfoData(wId);
               ThreadInfo beanInfo = threadInfos[i];
 
               info.setTimeStamp(timestamp);
@@ -247,7 +255,8 @@
             try {
 
                 ThreadMXBean bean = getDataCollectorBean(connection);
-                VMThreadCapabilities caps = new VMThreadCapabilities();
+                String wId = writerId.getWriterID();
+                VMThreadCapabilities caps = new VMThreadCapabilities(wId);
 
                 List<String> features = new ArrayList<>(3);
                 if (bean.isThreadCpuTimeSupported())
@@ -309,8 +318,9 @@
                 }
                 description = descriptionBuilder.toString();
             }
-
-            VmDeadLockData data = new VmDeadLockData();
+            
+            String wId = writerId.getWriterID();
+            VmDeadLockData data = new VmDeadLockData(wId);
             data.setTimeStamp(timeStamp);
             data.setVmId(vmId);
             data.setDeadLockDescription(description);
@@ -327,5 +337,6 @@
 
         return true;
     }
+    
 }
 
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadHarvester.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadHarvester.java	Mon Sep 02 11:34:12 2013 +0200
@@ -54,6 +54,7 @@
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Response.ResponseType;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.collector.HarvesterCommand;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
@@ -63,22 +64,24 @@
 
     private static final Logger logger = LoggingUtils.getLogger(ThreadHarvester.class);
     
-    private ScheduledExecutorService executor;
-    Map<String, Harvester> connectors;
+    private final ScheduledExecutorService executor;
+    final Map<String, Harvester> connectors;
 
+    private final Clock clock;
+    private final MXBeanConnectionPool connectionPool;
+    private final WriterID writerId;
     private ThreadDao dao;
-    private Clock clock;
-    private MXBeanConnectionPool connectionPool;
 
-    public ThreadHarvester(ScheduledExecutorService executor, MXBeanConnectionPool pool) {
-        this(executor, new SystemClock(), pool);
+    public ThreadHarvester(ScheduledExecutorService executor, MXBeanConnectionPool pool, WriterID writerID) {
+        this(executor, new SystemClock(), pool, writerID);
     }
     
-    public ThreadHarvester(ScheduledExecutorService executor, Clock clock, MXBeanConnectionPool connectionPool) {
+    public ThreadHarvester(ScheduledExecutorService executor, Clock clock, MXBeanConnectionPool connectionPool, WriterID writerId) {
         this.executor = executor;
         this.connectors = new HashMap<>();
         this.clock = clock;
         this.connectionPool = connectionPool;
+        this.writerId = writerId;
     }
     
     /**
@@ -192,7 +195,8 @@
     }
 
     private void updateHarvestingStatus(String vmId, boolean harvesting) {
-        ThreadHarvestingStatus status = new ThreadHarvestingStatus();
+        String wId = writerId.getWriterID();
+        ThreadHarvestingStatus status = new ThreadHarvestingStatus(wId);
         status.setTimeStamp(clock.getRealTimeMillis());
         status.setVmId(vmId);
         status.setHarvesting(harvesting);
@@ -210,7 +214,7 @@
     }
 
     Harvester createHarvester(String vmId, int pid) {
-        return new Harvester(dao, executor, vmId, pid, connectionPool);
+        return new Harvester(dao, executor, vmId, pid, connectionPool, writerId);
     }
 
     /**
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.java	Mon Sep 02 11:34:12 2013 +0200
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.thread.harvester.osgi;
 
+import java.util.Map;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 
@@ -48,7 +49,10 @@
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.agent.command.ReceiverRegistry;
 import com.redhat.thermostat.backend.Backend;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.harvester.ThreadBackend;
 import com.redhat.thermostat.thread.harvester.ThreadHarvester;
@@ -58,7 +62,7 @@
     
     private ScheduledExecutorService executor = Executors.newScheduledThreadPool(24);
 
-    private ServiceTracker connectionPoolTracker;
+    private MultipleServiceTracker connectionPoolTracker;
     private ServiceTracker threadDaoTracker;
     private ServiceRegistration backendRegistration;
 
@@ -68,20 +72,25 @@
     
     @Override
     public void start(final BundleContext context) throws Exception {
-
-        connectionPoolTracker = new ServiceTracker(context, MXBeanConnectionPool.class, null) {
+        
+        Class<?>[] deps = new Class<?>[] {
+                MXBeanConnectionPool.class,
+                WriterID.class,
+        };
+        connectionPoolTracker = new MultipleServiceTracker(context, deps, new Action() {
+            
             @Override
-            public Object addingService(ServiceReference reference) {
-                MXBeanConnectionPool pool =  (MXBeanConnectionPool) super.addingService(reference);
-                harvester = new ThreadHarvester(executor, pool);
-                return pool;
+            public void dependenciesAvailable(Map<String, Object> services) {
+                MXBeanConnectionPool pool = (MXBeanConnectionPool) services.get(MXBeanConnectionPool.class.getName());
+                WriterID writerId = (WriterID) services.get(WriterID.class.getName());
+                harvester = new ThreadHarvester(executor, pool, writerId);
             }
+
             @Override
-            public void removedService(ServiceReference reference, Object service) {
-                super.removedService(reference, service);
+            public void dependenciesUnavailable() {
                 harvester = null;
             }
-        };
+        });
         connectionPoolTracker.open();
 
         registry = new ReceiverRegistry(context);
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -57,10 +57,12 @@
 
 import javax.management.MalformedObjectNameException;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.common.Clock;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
 import com.redhat.thermostat.thread.model.ThreadSummary;
@@ -70,6 +72,13 @@
 import com.redhat.thermostat.utils.management.MXBeanConnectionPool;
 
 public class HarvesterTest {
+    
+    private WriterID writerId;
+    
+    @Before
+    public void setup() {
+        writerId = mock(WriterID.class);
+    }
 
     @Test
     public void testStart() {
@@ -86,7 +95,7 @@
         
         when(executor.scheduleAtFixedRate(arg0.capture(), arg1.capture(), arg2.capture(), arg3.capture())).thenReturn(null);
         
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool) {
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId) {
             @Override
             synchronized void harvestData() {
                 harvestDataCalled[0] = true;
@@ -130,7 +139,7 @@
         
         when(executor.scheduleAtFixedRate(arg0.capture(), arg1.capture(), arg2.capture(), arg3.capture())).thenReturn(null);
         
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool) {
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId) {
             @Override
             synchronized void harvestData() {
                 harvestDataCalled[0] = true;
@@ -170,7 +179,7 @@
         
         when(executor.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(future);
         
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool);
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId);
         
         harvester.start();
         
@@ -204,7 +213,7 @@
         
         when(executor.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(future);
         
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool);
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId);
         
         harvester.start();
         
@@ -232,7 +241,7 @@
         
         MXBeanConnectionPool pool = mock(MXBeanConnectionPool.class);
 
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool);
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId);
         
         verify(executor, times(0)).scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class));
         
@@ -286,7 +295,7 @@
 
         final boolean [] getDataCollectorBeanCalled = new boolean[1];
         
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool) {
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId) {
             @Override
             ThreadMXBean getDataCollectorBean(MXBeanConnection connection)
                     throws MalformedObjectNameException {
@@ -345,7 +354,7 @@
 
         final boolean [] getDataCollectorBeanCalled = new boolean[1];
         
-        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool) {
+        Harvester harvester = new Harvester(dao, executor, "vmId", 42, pool, writerId) {
             @Override
             ThreadMXBean getDataCollectorBean(MXBeanConnection connection)
                     throws MalformedObjectNameException {
@@ -387,7 +396,7 @@
 
         final boolean[] getDataCollectorBeanCalled = new boolean[1];
 
-        Harvester harvester = new Harvester(dao, executor, clock, "vmId", 42, pool) {
+        Harvester harvester = new Harvester(dao, executor, clock, "vmId", 42, pool, writerId) {
             @Override
             ThreadMXBean getDataCollectorBean(MXBeanConnection connection)
                     throws MalformedObjectNameException {
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadHarvesterTest.java	Mon Sep 02 11:32:11 2013 +0200
+++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadHarvesterTest.java	Mon Sep 02 11:34:12 2013 +0200
@@ -54,6 +54,7 @@
 import com.redhat.thermostat.common.command.Request;
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.thread.collector.HarvesterCommand;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
@@ -63,11 +64,13 @@
 
     private MXBeanConnectionPool pool;
     private ScheduledExecutorService executor;
+    private WriterID writerId;
 
     @Before
     public void setUp() {
         pool = mock(MXBeanConnectionPool.class);
         executor = mock(ScheduledExecutorService.class);
+        writerId = mock(WriterID.class);
     }
 
     @Test
@@ -87,7 +90,7 @@
             thenReturn("42").
             thenReturn("0xcafe");
         
-        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool) {
+        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool, writerId) {
             @Override
             Harvester createHarvester(String vmId, int pid) {
                 
@@ -126,7 +129,7 @@
             thenReturn(HarvesterCommand.STOP.name()).
             thenReturn("vmId");
         
-        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool) {
+        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool, writerId) {
             { connectors.put("vmId", harverster); }
         };
         threadHarvester.setThreadDao(dao);
@@ -158,7 +161,7 @@
                 thenReturn("42").
                 thenReturn("0xcafe");
 
-        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool) {
+        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool, writerId) {
             @Override
             Harvester createHarvester(String vmId, int pid) {
 
@@ -191,7 +194,7 @@
         final boolean[] createHarvesterCalled = new boolean[1];
         final Harvester harverster = mock(Harvester.class);
         
-        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool) {
+        ThreadHarvester threadHarvester = new ThreadHarvester(executor, pool, writerId) {
             @Override
             Harvester createHarvester(String vmId, int pid) {
                 
@@ -212,7 +215,7 @@
 
     @Test
     public void testRecieveWithoutDaosFails() {
-        ThreadHarvester harvester = new ThreadHarvester(executor, pool);
+        ThreadHarvester harvester = new ThreadHarvester(executor, pool, writerId);
         Response response = harvester.receive(mock(Request.class));
 
         assertEquals(ResponseType.ERROR, response.getType());
@@ -224,7 +227,7 @@
         when(clock.getRealTimeMillis()).thenReturn(1l);
         ThreadDao dao = mock(ThreadDao.class);
 
-        ThreadHarvester harvester = new ThreadHarvester(executor, clock, pool);
+        ThreadHarvester harvester = new ThreadHarvester(executor, clock, pool, writerId);
         harvester.setThreadDao(dao);
 
         harvester.addThreadHarvestingStatus("vmId");
@@ -244,7 +247,7 @@
         when(clock.getRealTimeMillis()).thenReturn(1l);
         ThreadDao dao = mock(ThreadDao.class);
 
-        ThreadHarvester harvester = new ThreadHarvester(executor, clock, pool);
+        ThreadHarvester harvester = new ThreadHarvester(executor, clock, pool, writerId);
         harvester.setThreadDao(dao);
 
         harvester.saveVmCaps("vmId", 10);
@@ -270,7 +273,7 @@
         when(javaHarvester.stop()).thenReturn(true);
         when(javaHarvester.getPid()).thenReturn(42);
 
-        ThreadHarvester harvester = new ThreadHarvester(executor, clock, pool) {
+        ThreadHarvester harvester = new ThreadHarvester(executor, clock, pool, writerId) {
             @Override
             Harvester createHarvester(String vmId, int pid) {
                 assertEquals("vmId", vmId);