changeset 1246:bac262a2c98f

Use WriterID service over Storage.get/setAgentId() (Part 1). Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-September/008097.html PR1509
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 02 Sep 2013 11:36:26 +0200
parents 484de0a847c4
children 352dd55544d0
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ListVMsCommandTest.java client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VMInfoCommandTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayModelTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java common/core/src/test/java/com/redhat/thermostat/common/cli/CommandRegistryImplTest.java host-overview/client-core/src/test/java/com/redhat/thermostat/host/overview/client/core/internal/HostOverviewControllerTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/WriterID.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/WriterIDImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/model/AgentInformation.java storage/core/src/main/java/com/redhat/thermostat/storage/model/BackendInformation.java storage/core/src/main/java/com/redhat/thermostat/storage/model/BasePojo.java storage/core/src/main/java/com/redhat/thermostat/storage/model/HostInfo.java storage/core/src/main/java/com/redhat/thermostat/storage/model/NetworkInterfaceInfo.java storage/core/src/main/java/com/redhat/thermostat/storage/model/VmInfo.java storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/model/BackendInformationTest.java storage/core/src/test/java/com/redhat/thermostat/storage/model/BasePojoTest.java storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java storage/core/src/test/java/com/redhat/thermostat/storage/model/TimeStampedPojoCorrelatorTest.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java system-backend/src/main/java/com/redhat/thermostat/backend/system/HostInfoBuilder.java system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java system-backend/src/main/java/com/redhat/thermostat/backend/system/NetworkInfoBuilder.java system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java system-backend/src/test/java/com/redhat/thermostat/backend/system/HostInfoBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/JvmStatHostListenerTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/NetworkInfoBuilderTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/TestObj.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java web/common/src/test/java/com/redhat/thermostat/web/common/ThermostatGSONConverterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseSerializerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java
diffstat 60 files changed, 610 insertions(+), 336 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java	Mon Sep 02 11:36:26 2013 +0200
@@ -36,49 +36,63 @@
 
 package com.redhat.thermostat.agent.cli.impl;
 
+import java.util.Map;
+
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
 
 import com.redhat.thermostat.agent.cli.impl.db.StorageCommand;
 import com.redhat.thermostat.common.ExitStatus;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+import com.redhat.thermostat.storage.core.WriterID;
 
 public class Activator implements BundleActivator {
 
     private CommandRegistry reg;
     private AgentApplication agentApplication;
-    @SuppressWarnings("rawtypes")
-    private ServiceTracker exitStatusTracker;
+    private MultipleServiceTracker tracker;
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Override
     public void start(final BundleContext context) throws Exception {
         reg = new CommandRegistryImpl(context);
-
-        exitStatusTracker = new ServiceTracker(context, ExitStatus.class, null) {
+        
+        Class<?>[] deps = new Class<?>[] {
+                ExitStatus.class,
+                WriterID.class // agent app uses it
+        };
+        tracker = new MultipleServiceTracker(context, deps, new Action() {
             
             @Override
-            public Object addingService(ServiceReference reference) {
-                ExitStatus exitStatus = (ExitStatus)context.getService(reference);
-                agentApplication = new AgentApplication(context, exitStatus);
+            public void dependenciesAvailable(Map<String, Object> services) {
+                ExitStatus exitStatus = (ExitStatus) services.get(ExitStatus.class.getName());
+                WriterID writerID = (WriterID) services.get(WriterID.class.getName());
+                agentApplication = new AgentApplication(context, exitStatus, writerID);
                 reg.registerCommand("service", new ServiceCommand(context));
                 reg.registerCommand("storage", new StorageCommand(exitStatus));
                 reg.registerCommand("agent", agentApplication);
-                return exitStatus;
             }
-            
-        };
-        exitStatusTracker.open();
+
+            @Override
+            public void dependenciesUnavailable() {
+                agentApplication.shutdown();
+                reg.unregisterCommands();
+            }
+        });
+        tracker.open();
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        agentApplication.shutdown();
+        if (agentApplication != null) {
+            // Bundle may be shut down *before* deps become available and
+            // app is set.
+            agentApplication.shutdown();
+        }
         reg.unregisterCommands();
-        exitStatusTracker.close();
+        tracker.close();
     }
 }
 
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java	Mon Sep 02 11:36:26 2013 +0200
@@ -71,6 +71,7 @@
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.storage.core.DbServiceFactory;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 
@@ -89,17 +90,19 @@
     private ServiceTracker configServerTracker;
     private MultipleServiceTracker daoTracker;
     private final ExitStatus exitStatus;
+    private final WriterID writerId;
     private CountDownLatch shutdownLatch;
 
-    public AgentApplication(BundleContext bundleContext, ExitStatus exitStatus) {
-        this(bundleContext, exitStatus, new ConfigurationCreator(), new DbServiceFactory());
+    public AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, WriterID writerId) {
+        this(bundleContext, exitStatus, writerId, new ConfigurationCreator(), new DbServiceFactory());
     }
 
-    AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, ConfigurationCreator configurationCreator, DbServiceFactory dbServiceFactory) {
+    AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, WriterID writerId, ConfigurationCreator configurationCreator, DbServiceFactory dbServiceFactory) {
         this.bundleContext = bundleContext;
         this.configurationCreator = configurationCreator;
         this.dbServiceFactory = dbServiceFactory;
         this.exitStatus = exitStatus;
+        this.writerId = writerId;
     }
     
     private void parseArguments(Arguments args) throws InvalidConfigurationException {
@@ -246,7 +249,7 @@
             throw new RuntimeException(e);
         }
 
-        final Agent agent = new Agent(backendRegistry, configuration, storage, agentInfoDAO, backendInfoDAO);
+        final Agent agent = new Agent(backendRegistry, configuration, storage, agentInfoDAO, backendInfoDAO, writerId);
         try {
             logger.fine("Starting agent.");
             agent.start();
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java	Mon Sep 02 11:36:26 2013 +0200
@@ -41,7 +41,6 @@
 import java.util.concurrent.Semaphore;
 
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
 
 import com.redhat.thermostat.agent.cli.impl.db.StorageAlreadyRunningException;
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -44,6 +44,7 @@
 
 import com.redhat.thermostat.agent.cli.impl.db.StorageCommand;
 import com.redhat.thermostat.common.ExitStatus;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
 public class ActivatorTest {
@@ -51,22 +52,28 @@
     @Test
     public void verifyActivatorRegistersCommands() throws Exception {        
         StubBundleContext bundleContext = new StubBundleContext();
+
         ExitStatus exitStatus = mock(ExitStatus.class);
+        WriterID writerID = mock(WriterID.class);
+        bundleContext.registerService(WriterID.class, writerID, null);
         bundleContext.registerService(ExitStatus.class, exitStatus, null);
         
         Activator activator = new Activator();
 
+        assertEquals(0, bundleContext.getServiceListeners().size());
+        
         activator.start(bundleContext);
-
+        
+        assertEquals(2, bundleContext.getServiceListeners().size());
+        
         assertCommandIsRegistered(bundleContext, "agent", AgentApplication.class);
-
         assertCommandIsRegistered(bundleContext, "service", ServiceCommand.class);
-
         assertCommandIsRegistered(bundleContext, "storage", StorageCommand.class);
 
         activator.stop(bundleContext);
 
-        assertEquals(1, bundleContext.getAllServices().size());
+        assertEquals(0, bundleContext.getServiceListeners().size());
+        assertEquals(2, bundleContext.getAllServices().size());
     }
 }
 
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -39,7 +39,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
@@ -80,6 +79,7 @@
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.storage.core.DbServiceFactory;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.testutils.StubBundleContext;
@@ -98,6 +98,7 @@
     private ConfigurationCreator configCreator;
     private ExitStatus exitStatus;
     private DbServiceFactory dbServiceFactory;
+    private WriterID writerId;
     
     @Before
     public void setUp() throws InvalidConfigurationException {
@@ -121,6 +122,7 @@
         context.registerService(ConfigurationServer.class.getName(), configServer, null);
         dbServiceFactory = mock(DbServiceFactory.class);
         dbService = mock(DbService.class);
+        writerId = mock(WriterID.class);
         when(dbServiceFactory.createDbService(anyString(), anyString(), anyString())).thenReturn(dbService);
 
         exitStatus = mock(ExitStatus.class);
@@ -138,7 +140,7 @@
 
     @Test
     public void testAgentStartup() throws CommandException, InterruptedException {
-        final AgentApplication agent = new AgentApplication(context, exitStatus, configCreator, dbServiceFactory);
+        final AgentApplication agent = new AgentApplication(context, exitStatus, writerId, configCreator, dbServiceFactory);
         final CountDownLatch latch = new CountDownLatch(1);
         final CommandException[] ce = new CommandException[1];
         final long timeoutMillis = 5000L;
@@ -175,7 +177,7 @@
                 .withArguments(any(BundleContext.class))
                 .thenThrow(InvalidSyntaxException.class);
         final AgentApplication agent = new AgentApplication(context,
-                exitStatus, configCreator, dbServiceFactory);
+                exitStatus, writerId, configCreator, dbServiceFactory);
         try {
             agent.startAgent(null, null, null);
         } catch (RuntimeException e) {
@@ -193,13 +195,13 @@
         Agent mockAgent = mock(Agent.class);
         whenNew(Agent.class).withParameterTypes(BackendRegistry.class,
                 AgentStartupConfiguration.class, Storage.class,
-                AgentInfoDAO.class, BackendInfoDAO.class).withArguments(
+                AgentInfoDAO.class, BackendInfoDAO.class, WriterID.class).withArguments(
                 any(BackendRegistry.class),
                 any(AgentStartupConfiguration.class), any(Storage.class),
-                any(AgentInfoDAO.class), any(BackendInfoDAO.class)).thenReturn(mockAgent);
+                any(AgentInfoDAO.class), any(BackendInfoDAO.class), any(WriterID.class)).thenReturn(mockAgent);
         doThrow(LaunchException.class).when(mockAgent).start();
         final AgentApplication agent = new AgentApplication(context,
-                exitStatus, configCreator, dbServiceFactory);
+                exitStatus, writerId, configCreator, dbServiceFactory);
         try {
             agent.startAgent(null, null, null);
         } catch (RuntimeException e) {
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Mon Sep 02 11:36:26 2013 +0200
@@ -37,7 +37,6 @@
 package com.redhat.thermostat.agent;
 
 import java.util.Map;
-import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -51,6 +50,7 @@
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
@@ -63,18 +63,17 @@
 
     private static final Logger logger = LoggingUtils.getLogger(Agent.class);
 
-    private final UUID id;
     private final BackendRegistry backendRegistry;
     private final AgentStartupConfiguration config;
-
-    private AgentInformation agentInfo;
+    private final Map<Backend, BackendInformation> backendInfos;
+    private final Storage storage;
+    private final AgentInfoDAO agentDao;
+    private final BackendInfoDAO backendDao;
+    private final WriterID writerID;
     
-    private Map<Backend, BackendInformation> backendInfos;
-
-    private Storage storage;
-    private AgentInfoDAO agentDao;
-    private BackendInfoDAO backendDao;
+    private AgentInformation agentInfo;
     private boolean started = false;
+    
 
     private ActionListener<ThermostatExtensionRegistry.Action> backendRegistryListener =
             new ActionListener<ThermostatExtensionRegistry.Action>()
@@ -121,25 +120,15 @@
             }
         }
     };
-    
-    public Agent(BackendRegistry backendRegistry,
-            AgentStartupConfiguration config, Storage storage,
-            AgentInfoDAO agentInfoDao, BackendInfoDAO backendInfoDao) {
-        this(backendRegistry, UUID.randomUUID(), config, storage, agentInfoDao,
-                backendInfoDao);
-    }
 
-    public Agent(BackendRegistry registry, UUID agentId,
-            AgentStartupConfiguration config, Storage storage,
-            AgentInfoDAO agentInfoDao, BackendInfoDAO backendInfoDao) {
-        this.id = agentId;
+    public Agent(BackendRegistry registry, AgentStartupConfiguration config, Storage storage,
+            AgentInfoDAO agentInfoDao, BackendInfoDAO backendInfoDao, WriterID writerId) {
         this.backendRegistry = registry;
         this.config = config;
         this.storage = storage;
-        this.storage.setAgentId(agentId);
         this.agentDao = agentInfoDao;
         this.backendDao = backendInfoDao;
-
+        this.writerID = writerId;
         backendInfos = new ConcurrentHashMap<>();
         
         backendRegistry.addActionListener(backendRegistryListener);
@@ -148,7 +137,7 @@
     public synchronized void start() throws LaunchException {
         if (!started) {
             agentInfo = createAgentInformation();
-            agentInfo.setAgentId(id.toString());
+            agentInfo.setAgentId(getId());
             agentDao.addAgentInformation(agentInfo);
             
             backendRegistry.start();
@@ -164,7 +153,8 @@
     }
     
     private AgentInformation createAgentInformation() {
-        AgentInformation agentInfo = new AgentInformation();
+        String writerId = getId();
+        AgentInformation agentInfo = new AgentInformation(writerId);
         agentInfo.setStartTime(config.getStartTime());
         agentInfo.setAlive(true);
         agentInfo.setConfigListenAddress(config.getConfigListenAddress());
@@ -172,8 +162,8 @@
     }
 
     private BackendInformation createBackendInformation(Backend backend) {
-
-        BackendInformation backendInfo = new BackendInformation();
+        String writerId = getId();
+        BackendInformation backendInfo = new BackendInformation(writerId);
         backendInfo.setName(backend.getName());
         backendInfo.setDescription(backend.getDescription());
         backendInfo.setObserveNewJvm(backend.getObserveNewJvm());
@@ -212,9 +202,9 @@
         agentInfo.setAlive(false);
         agentDao.updateAgentInformation(agentInfo);
     }
-
-    public UUID getId() {
-        return id;
+    
+    public String getId() {
+        return writerID.getWriterID();
     }
 
 }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java	Mon Sep 02 11:36:26 2013 +0200
@@ -44,6 +44,7 @@
 import com.redhat.thermostat.backend.internal.BackendException;
 import com.redhat.thermostat.backend.internal.VmMonitor;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
 
 /**
  * This class is a convenient subclass of {@link Backend} (via {@link BaseBackend}) for those
@@ -59,17 +60,21 @@
     private static final Logger logger = LoggingUtils.getLogger(VmListenerBackend.class);
     
     private final VmStatusListenerRegistrar registrar;
+    private final WriterID writerId;
     private VmMonitor monitor;
     private boolean started;
 
     public VmListenerBackend(String backendName, String description,
-            String vendor, String version, VmStatusListenerRegistrar registrar) {
-        this(backendName, description, vendor, version, false, registrar);
+            String vendor, String version, VmStatusListenerRegistrar registrar,
+            WriterID writerId) {
+        this(backendName, description, vendor, version, false, registrar, writerId);
     }
     public VmListenerBackend(String backendName, String description,
-            String vendor, String version, boolean observeNewJvm, VmStatusListenerRegistrar registrar) {
+            String vendor, String version, boolean observeNewJvm,
+            VmStatusListenerRegistrar registrar, WriterID writerId) {
         super(backendName, description, vendor, version, observeNewJvm);
         this.registrar = registrar;
+        this.writerId = writerId;
         try {
             this.monitor = new VmMonitor();
         } catch (BackendException e) {
@@ -123,7 +128,8 @@
             /* fall-through */
         case VM_ACTIVE:
             if (getObserveNewJvm()) {
-                VmUpdateListener listener = createVmListener(vmId, pid);
+                String wId = writerId.getWriterID();
+                VmUpdateListener listener = createVmListener(wId, vmId, pid);
                 monitor.handleNewVm(listener, pid);
             } else {
                 logger.log(Level.FINE, "skipping new vm " + pid);
@@ -146,7 +152,7 @@
      * @param pid the process ID of the JVM
      * @return a new listener for the VM specified by pid
      */
-    protected abstract VmUpdateListener createVmListener(String vmId, int pid);
+    protected abstract VmUpdateListener createVmListener(String writerId, String vmId, int pid);
     
     /*
      * For testing purposes only.
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -61,6 +61,7 @@
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
@@ -99,7 +100,7 @@
     @SuppressWarnings("unused")
     @Test
     public void testAgentInit() throws Exception {
-        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao);
+        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao, null);
         
         verify(backendRegistry).addActionListener(any(ActionListener.class));
     }
@@ -109,7 +110,9 @@
         
         // Start agent.
         UUID uuid = UUID.randomUUID();
-        Agent agent = new Agent(backendRegistry, uuid, config, storage, agentInfoDao, backendInfoDao);
+        WriterID id = mock(WriterID.class);
+        when(id.getWriterID()).thenReturn(uuid.toString());
+        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao, id);
         
         agent.start();
 
@@ -127,7 +130,8 @@
         ArgumentCaptor<ActionListener> backendListener = ArgumentCaptor.forClass(ActionListener.class);
 
         // Start agent.
-        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao);
+        WriterID id = mock(WriterID.class);
+        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao, id);
         verify(backendRegistry).addActionListener(backendListener.capture());
         
         agent.start();
@@ -173,7 +177,9 @@
     public void testStopAgentWithPurging() throws Exception {
                 
         UUID uuid = UUID.randomUUID();
-        Agent agent = new Agent(backendRegistry, uuid, config, storage, agentInfoDao, backendInfoDao);
+        WriterID id = mock(WriterID.class);
+        when(id.getWriterID()).thenReturn(uuid.toString());
+        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao, id);
         agent.start();
         
         // stop agent
@@ -193,7 +199,8 @@
         when(config.getStartTime()).thenReturn(123L);
         when(config.purge()).thenReturn(false);
         
-        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao);
+        WriterID id = mock(WriterID.class);
+        Agent agent = new Agent(backendRegistry, config, storage, agentInfoDao, backendInfoDao, id);
         agent.start();
         
         // stop agent
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -53,6 +53,7 @@
 import com.redhat.thermostat.agent.VmStatusListener.Status;
 import com.redhat.thermostat.agent.VmStatusListenerRegistrar;
 import com.redhat.thermostat.backend.internal.VmMonitor;
+import com.redhat.thermostat.storage.core.WriterID;
 
 public class VmListenerBackendTest {
     private static final String VM_ID = "vmId";
@@ -66,8 +67,9 @@
     @Before
     public void setup() {
         registrar = mock(VmStatusListenerRegistrar.class);
+        WriterID id = mock(WriterID.class);
         backend = new TestBackend("Test Backend", "Backend for test", "Test Co.",
-                "0.0.0", registrar);
+                "0.0.0", registrar, id);
         monitor = mock(VmMonitor.class);
         listener = mock(VmUpdateListener.class);
         backend.setMonitor(monitor);
@@ -156,8 +158,8 @@
     private class TestBackend extends VmListenerBackend {
 
         public TestBackend(String name, String description, String vendor,
-                String version, VmStatusListenerRegistrar registrar) {
-            super(name, description, vendor, version, registrar);
+                String version, VmStatusListenerRegistrar registrar, WriterID writerId) {
+            super(name, description, vendor, version, registrar, writerId);
         }
 
         @Override
@@ -166,7 +168,7 @@
         }
 
         @Override
-        protected VmUpdateListener createVmListener(String vmId, int pid) {
+        protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) {
             return listener;
         }
         
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ListVMsCommandTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ListVMsCommandTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -102,7 +102,7 @@
         HostRef host1 = new HostRef("123", "h1");
         String vmId = "vmId";
         VmRef vm1 = new VmRef(host1, vmId, 1, "n");
-        VmInfo vm1Info = new VmInfo(vmId, 1, 0, 1, "", "", "", "", "", "", "", "", null, null, null, -1, null);
+        VmInfo vm1Info = new VmInfo("foo", vmId, 1, 0, 1, "", "", "", "", "", "", "", "", null, null, null, -1, null);
         when(hostsDAO.getHosts()).thenReturn(Arrays.asList(host1));
         when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(vm1));
         when(vmsDAO.getVmInfo(eq(vm1))).thenReturn(vm1Info);
@@ -131,7 +131,7 @@
         VmRef vm2 = new VmRef(host1, "vm2", 2, "n1");
         VmRef vm3 = new VmRef(host2, "vm3", 123456, "longvmname");
 
-        VmInfo vmInfo = new VmInfo("vm1", 1, 0, 1, "", "", "", "", "", "", "", "", null, null, null, -1, null);
+        VmInfo vmInfo = new VmInfo("foo", "vm1", 1, 0, 1, "", "", "", "", "", "", "", "", null, null, null, -1, null);
 
         when(vmsDAO.getVMs(host1)).thenReturn(Arrays.asList(vm1, vm2));
         when(vmsDAO.getVMs(host2)).thenReturn(Arrays.asList(vm3));
--- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VMInfoCommandTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VMInfoCommandTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -107,7 +107,7 @@
         start.set(2012, 5, 7, 15, 32, 0);
         Calendar end = Calendar.getInstance();
         end.set(2013, 10, 1, 1, 22, 0);
-        VmInfo vmInfo = new VmInfo(VM_ID, 234, start.getTimeInMillis(), end.getTimeInMillis(), "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0], 2000, "myUser");
+        VmInfo vmInfo = new VmInfo("foo", VM_ID, 234, start.getTimeInMillis(), end.getTimeInMillis(), "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0], 2000, "myUser");
         when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
         when(vmsDAO.getVmInfo(new VmRef(host, "noVm", -1, "dummy"))).thenThrow(new DAOException("Unknown VM ID: noVm"));
         when(vmsDAO.getVMs(host)).thenReturn(Arrays.asList(vm));
@@ -243,7 +243,7 @@
         Calendar start = Calendar.getInstance();
         start.set(2012, 5, 7, 15, 32, 0);
         final String vmId = "61a255db-1c27-43d6-aaee-28bb4788b8db";
-        VmInfo vmInfo = new VmInfo(vmId, 234, start.getTimeInMillis(), Long.MIN_VALUE, "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0], 2000, "myUser");
+        VmInfo vmInfo = new VmInfo("foo", vmId, 234, start.getTimeInMillis(), Long.MIN_VALUE, "vmVersion", "javaHome", "mainClass", "commandLine", "vmName", "vmInfo", "vmVersion", "vmArguments", new HashMap<String,String>(), new HashMap<String,String>(), new String[0], 2000, "myUser");
         when(vmsDAO.getVmInfo(vm)).thenReturn(vmInfo);
 
         SimpleArguments args = new SimpleArguments();
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayControllerTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayControllerTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -69,10 +69,9 @@
     }
 
     private void setUpAgentAndBackendInformation() {
-        agentInfo1 = new AgentInformation();
-        agentInfo1.setAgentId("agent-1");
+        agentInfo1 = new AgentInformation("agent-1");
 
-        backendInfo1 = new BackendInformation();
+        backendInfo1 = new BackendInformation("agent-1");
         backendInfo1.setName("backend-1");
         backendInfo1.setDescription("backend-description1");
     }
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayModelTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayModelTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -51,8 +51,8 @@
 
 public class AgentInformationDisplayModelTest {
 
-    private AgentInformation agentInfo1 = new AgentInformation();
-    private AgentInformation agentInfo2 = new AgentInformation();
+    private AgentInformation agentInfo1 = new AgentInformation("agent-1");
+    private AgentInformation agentInfo2 = new AgentInformation("agent-2");
 
     private AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
     private BackendInfoDAO backendInfoDao = mock(BackendInfoDAO.class);
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -570,7 +570,7 @@
 
     @Test
     public void verityVMActionsAreShown() {
-        VmInfo vmInfo = new VmInfo("123", 0, 1, 2, null, null, null, null, null, null, null, null, null, null, null, -1, null);
+        VmInfo vmInfo = new VmInfo("foo", "123", 0, 1, 2, null, null, null, null, null, null, null, null, null, null, null, -1, null);
         when(mockVmsDAO.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo);
 
         VmRef ref = mock(VmRef.class);
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandRegistryImpl.java	Mon Sep 02 11:36:26 2013 +0200
@@ -50,7 +50,7 @@
 public class CommandRegistryImpl implements CommandRegistry {
 
     private BundleContext context;
-    private Collection<ServiceRegistration> myRegisteredCommands;
+    private Collection<ServiceRegistration<?>> myRegisteredCommands;
 
     public CommandRegistryImpl(BundleContext ctx) {
         context = ctx;
@@ -64,15 +64,17 @@
 
         Hashtable<String,String> props = new Hashtable<>();
         props.put(Command.NAME, name);
-        ServiceRegistration registration = context.registerService(Command.class.getName(), cmd, props);
+        ServiceRegistration<?> registration = context.registerService(Command.class.getName(), cmd, props);
         myRegisteredCommands.add(registration);
     }
 
     @Override
     public void unregisterCommands() {
-        for (ServiceRegistration reg : myRegisteredCommands) {
+        for (ServiceRegistration<?> reg : myRegisteredCommands) {
             reg.unregister();
         }
+        // we've just unregistered commands
+        myRegisteredCommands.clear();
     }
 
 }
--- a/common/core/src/test/java/com/redhat/thermostat/common/cli/CommandRegistryImplTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/cli/CommandRegistryImplTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -38,6 +38,7 @@
 
 import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 
 import org.junit.After;
@@ -96,6 +97,32 @@
 
         assertEquals(0, bundleContext.getAllServices().size());
     }
+    
+    @Test
+    public void testUnregisterCommandsMultipleTimes() {
+        Command cmd1 = mock(Command.class);
+        String name1 = "test1";
+        Command cmd2 = mock(Command.class);
+        String name2 = "test2";
+
+        commandRegistry.registerCommand(name1, cmd1);
+        commandRegistry.registerCommand(name2, cmd2);
+
+        assertEquals(2, bundleContext.getAllServices().size());
+
+        commandRegistry.unregisterCommands();
+
+        assertEquals(0, bundleContext.getAllServices().size());
+        
+        try {
+            commandRegistry.unregisterCommands();
+            // pass
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail("unregistering commands should have cleared services registrations");
+        }
+        assertEquals(0, bundleContext.getAllServices().size());
+    }
 
 }
 
--- a/host-overview/client-core/src/test/java/com/redhat/thermostat/host/overview/client/core/internal/HostOverviewControllerTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/host-overview/client-core/src/test/java/com/redhat/thermostat/host/overview/client/core/internal/HostOverviewControllerTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -99,10 +99,10 @@
         when(appSvc.getTimerFactory()).thenReturn(timerFactory);
 
         // Setup DAOs
-        HostInfo hostInfo = new HostInfo(HOST_NAME, OS_NAME, KERNEL_NAME, CPU_MODEL, CPU_COUNT, TOTAL_MEMORY);
+        HostInfo hostInfo = new HostInfo("foo", HOST_NAME, OS_NAME, KERNEL_NAME, CPU_MODEL, CPU_COUNT, TOTAL_MEMORY);
 
         List<NetworkInterfaceInfo> networkInfo = new ArrayList<NetworkInterfaceInfo>();
-        NetworkInterfaceInfo ifaceInfo = new NetworkInterfaceInfo(NETWORK_INTERFACE);
+        NetworkInterfaceInfo ifaceInfo = new NetworkInterfaceInfo("foo", NETWORK_INTERFACE);
         ifaceInfo.setIp4Addr(IPV4_ADDR);
         ifaceInfo.setIp6Addr(IPV6_ADDR);
         networkInfo.add(ifaceInfo);
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -160,8 +160,7 @@
         storage.registerCategory(CpuStatDAO.cpuStatCategory);
 
         for (int i = 0; i < numberOfItems; i++) {
-            CpuStat pojo = new CpuStat(i, new double[] {i, i*2});
-            pojo.setAgentId("test-agent-id");
+            CpuStat pojo = new CpuStat("test-agent-id", i, new double[] {i, i*2});
             Add add = storage.createAdd(CpuStatDAO.cpuStatCategory);
             add.setPojo(pojo);
             add.apply();
@@ -502,20 +501,18 @@
     }
 
     @Test
-    public void setDefaultAgentID() throws Exception {
+    public void storagePurge() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch);
         BackingStorage mongoStorage = getAndConnectStorage(listener);
         latch.await();
         mongoStorage.getConnection().removeListener(listener);
         UUID uuid = new UUID(42, 24);
-        mongoStorage.setAgentId(uuid);
 
         mongoStorage.registerCategory(VmCpuStatDAO.vmCpuStatCategory);
         long timeStamp = 5;
         double cpuLoad = 0.15;
-        VmCpuStat pojo = new VmCpuStat(timeStamp, VM_ID1, cpuLoad);
-        // Note: agentId not set on pojo
+        VmCpuStat pojo = new VmCpuStat(uuid.toString(), timeStamp, VM_ID1, cpuLoad);
         Add add = mongoStorage.createAdd(VmCpuStatDAO.vmCpuStatCategory);
         add.setPojo(pojo);
         add.apply();
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -385,8 +385,7 @@
         storage.registerCategory(CpuStatDAO.cpuStatCategory);
 
         for (int i = 0; i < numberOfItems; i++) {
-            CpuStat pojo = new CpuStat(i, new double[] {i, i*2});
-            pojo.setAgentId("test-agent-id");
+            CpuStat pojo = new CpuStat("test-agent-id", i, new double[] {i, i*2});
             Add add = storage.createAdd(CpuStatDAO.cpuStatCategory);
             add.setPojo(pojo);
             add.apply();
@@ -406,8 +405,7 @@
         storage.registerCategory(HostInfoDAO.hostInfoCategory);
 
         for (int i = 0; i < numberOfItems; i++) {
-            HostInfo hostInfo = new HostInfo("foo " + i, "linux " + i, "kernel", "t8", i, i * 1000);
-            hostInfo.setAgentId("test-host-agent-id");
+            HostInfo hostInfo = new HostInfo("test-host-agent-id", "foo " + i, "linux " + i, "kernel", "t8", i, i * 1000);
             Add add = storage.createAdd(HostInfoDAO.hostInfoCategory);
             add.setPojo(hostInfo);
             add.apply();
@@ -857,7 +855,7 @@
     }
 
     @Test
-    public void setDefaultAgentID() throws Exception {
+    public void storagePurge() throws Exception {
         String[] roleNames = new String[] {
                 Roles.ACCESS_REALM,
                 Roles.LOGIN,
@@ -870,13 +868,10 @@
         };
         Storage storage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         UUID uuid = new UUID(42, 24);
-        storage.setAgentId(uuid);
-
         storage.registerCategory(VmCpuStatDAO.vmCpuStatCategory);
         long timeStamp = 5;
         double cpuLoad = 0.15;
-        VmCpuStat pojo = new VmCpuStat(timeStamp, VM_ID1, cpuLoad);
-        // Note: agentId not set on pojo
+        VmCpuStat pojo = new VmCpuStat(uuid.toString(), timeStamp, VM_ID1, cpuLoad);
         Add add = storage.createAdd(VmCpuStatDAO.vmCpuStatCategory);
         add.setPojo(pojo);
         add.apply();
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Mon Sep 02 11:36:26 2013 +0200
@@ -39,7 +39,6 @@
 
 import java.io.InputStream;
 import java.util.Objects;
-import java.util.UUID;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -238,25 +237,6 @@
     }
 
     @Override
-    public void setAgentId(final UUID id) {
-
-        executor.execute(new Runnable() {
-            
-            @Override
-            public void run() {
-                delegate.setAgentId(id);
-            }
-
-        });
-
-    }
-
-    @Override
-    public String getAgentId() {
-        return delegate.getAgentId();
-    }
-
-    @Override
     public void registerCategory(final Category<?> category) {
         delegate.registerCategory(category);
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Mon Sep 02 11:36:26 2013 +0200
@@ -37,7 +37,6 @@
 package com.redhat.thermostat.storage.core;
 
 import java.io.InputStream;
-import java.util.UUID;
 
 import com.redhat.thermostat.annotations.Service;
 import com.redhat.thermostat.storage.model.Pojo;
@@ -50,10 +49,6 @@
 @Service
 public interface Storage {
 
-    void setAgentId(UUID id);
-
-    String getAgentId();
-
     void registerCategory(Category<?> category);
     
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/WriterID.java	Mon Sep 02 11:36:26 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.storage.core;
+
+import com.redhat.thermostat.annotations.Service;
+
+/**
+ * Service interface class for getting the writer ID which should
+ * be used for writing data to {@link Storage}.
+ *
+ * @see Key#AGENT_ID
+ */
+@Service
+public interface WriterID {
+
+    /**
+     * 
+     * @return the writer ID.
+     */
+    String getWriterID();
+}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java	Mon Sep 02 11:36:26 2013 +0200
@@ -38,6 +38,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -46,6 +47,7 @@
 import org.osgi.util.tracker.ServiceTracker;
 
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
@@ -59,8 +61,10 @@
 
 public class Activator implements BundleActivator {
     
-    ServiceTracker tracker;
-    List<ServiceRegistration> regs;
+    private static final String WRITER_UUID = UUID.randomUUID().toString();
+    
+    ServiceTracker<Storage, Storage> tracker;
+    List<ServiceRegistration<?>> regs;
     
     public Activator() {
         regs = new ArrayList<>();
@@ -68,12 +72,19 @@
 
     @Override
     public void start(BundleContext context) throws Exception {
-        tracker = new ServiceTracker(context, Storage.class, null) {
+        // WriterID has to be registered unconditionally (at least not as part
+        // of the Storage.class tracker, since that is only registered once
+        // storage is connected).
+        final WriterID writerID = new WriterIDImpl(WRITER_UUID);
+        ServiceRegistration<?> reg = context.registerService(WriterID.class, writerID, null);
+        regs.add(reg);
+        
+        tracker = new ServiceTracker<Storage, Storage>(context, Storage.class, null) {
             @Override
-            public Object addingService(ServiceReference reference) {
+            public Storage addingService(ServiceReference<Storage> reference) {
                 Storage storage = (Storage) super.addingService(reference);
                 AgentInfoDAO agentInfoDao = new AgentInfoDAOImpl(storage);
-                ServiceRegistration reg = context.registerService(AgentInfoDAO.class.getName(), agentInfoDao, null);
+                ServiceRegistration<?> reg = context.registerService(AgentInfoDAO.class.getName(), agentInfoDao, null);
                 regs.add(reg);
                 BackendInfoDAO backendInfoDao = new BackendInfoDAOImpl(storage);
                 reg = context.registerService(BackendInfoDAO.class.getName(), backendInfoDao, null);
@@ -91,12 +102,9 @@
             }
             
             @Override
-            public void removedService(ServiceReference reference,
-                    Object service) {
-                for (ServiceRegistration reg : regs) {
-                    reg.unregister();
-                }
-                regs.clear();
+            public void removedService(ServiceReference<Storage> reference,
+                    Storage service) {
+                unregisterServices();
                 super.removedService(reference, service);
             }
         };
@@ -104,8 +112,16 @@
         tracker.open();
     }
 
+    private void unregisterServices() {
+        for (ServiceRegistration<?> reg : regs) {
+            reg.unregister();
+        }
+        regs.clear();
+    }
+
     @Override
     public void stop(BundleContext context) throws Exception {
+        unregisterServices();
         tracker.close();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/WriterIDImpl.java	Mon Sep 02 11:36:26 2013 +0200
@@ -0,0 +1,54 @@
+/*
+ * 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.storage.internal;
+
+import com.redhat.thermostat.storage.core.WriterID;
+
+public class WriterIDImpl implements WriterID {
+    
+    private final String writerId;
+    
+    public WriterIDImpl(String writerId) {
+        this.writerId = writerId;
+    }
+
+    @Override
+    public String getWriterID() {
+        return writerId;
+    }
+
+}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Mon Sep 02 11:36:26 2013 +0200
@@ -64,7 +64,7 @@
             + networkInfoCategory.getName() + " WHERE '"
             + Key.AGENT_ID.getName() + "' = ?s";
 
-    private Storage storage;
+    private final Storage storage;
 
     public NetworkInterfaceInfoDAOImpl(Storage storage) {
         this.storage = storage;
@@ -103,9 +103,6 @@
         Replace<NetworkInterfaceInfo> replace = storage.createReplace(networkInfoCategory);
         ExpressionFactory factory = new ExpressionFactory();
         String agentId = info.getAgentId();
-        if (agentId == null) {
-            agentId = storage.getAgentId();
-        }
         Expression left = factory.equalTo(Key.AGENT_ID, agentId);
         Expression right = factory.equalTo(NetworkInterfaceInfoDAO.ifaceKey, info.getInterfaceName());
         Expression expression = factory.and(left, right); 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/AgentInformation.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/AgentInformation.java	Mon Sep 02 11:36:26 2013 +0200
@@ -55,6 +55,14 @@
     @SuppressWarnings("unused")
     private List<BackendInformation> backends = new ArrayList<BackendInformation>();
 
+    public AgentInformation() {
+        this(null);
+    }
+    
+    public AgentInformation(String writerId) {
+        super(writerId);
+    }
+    
     @Persist
     public long getStartTime() {
         return startTime;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/BackendInformation.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/BackendInformation.java	Mon Sep 02 11:36:26 2013 +0200
@@ -56,6 +56,14 @@
     private int orderValue;
     private Map<String, String> configuration = new HashMap<String,String>();
 
+    public BackendInformation() {
+        this(null);
+    }
+    
+    public BackendInformation(String writerId) {
+        super(writerId);
+    }
+    
     @Persist
     public String getName() {
         return name;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/BasePojo.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/BasePojo.java	Mon Sep 02 11:36:26 2013 +0200
@@ -44,6 +44,10 @@
 public class BasePojo implements Pojo {
 
     private String agentId;
+    
+    public BasePojo(String writerId) {
+        this.agentId = writerId;
+    }
 
     @Persist
     public final String getAgentId() {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/HostInfo.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/HostInfo.java	Mon Sep 02 11:36:26 2013 +0200
@@ -50,10 +50,11 @@
     private long totalMemory;
 
     public HostInfo() {
-        this(null, null, null, null, -1, -1);
+        this(null, null, null, null, null, -1, -1);
     }
 
-    public HostInfo(String hostname, String osName, String osKernel, String cpuModel, int cpuCount, long totalMemory) {
+    public HostInfo(String writerId, String hostname, String osName, String osKernel, String cpuModel, int cpuCount, long totalMemory) {
+        super(writerId);
         this.hostname = hostname;
         this.osName = osName;
         this.osKernel = osKernel;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/NetworkInterfaceInfo.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/NetworkInterfaceInfo.java	Mon Sep 02 11:36:26 2013 +0200
@@ -47,10 +47,11 @@
     private String ip6Addr;
 
     public NetworkInterfaceInfo() {
-        super();
+        this(null, null);
     }
 
-    public NetworkInterfaceInfo(String iFace) {
+    public NetworkInterfaceInfo(String writerId, String iFace) {
+        super(writerId);
         this.iFace = iFace;
         this.ip4Addr = null;
         this.ip6Addr = null;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/VmInfo.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/VmInfo.java	Mon Sep 02 11:36:26 2013 +0200
@@ -104,14 +104,16 @@
 
     public VmInfo() {
         /* use defaults */
+        super(null);
     }
 
-    public VmInfo(String vmId, int vmPid, long startTime, long stopTime,
+    public VmInfo(String writerId, String vmId, int vmPid, long startTime, long stopTime,
             String javaVersion, String javaHome,
             String mainClass, String commandLine,
             String vmName, String vmInfo, String vmVersion, String vmArguments,
             Map<String, String> properties, Map<String, String> environment, String[] loadedNativeLibraries,
             long uid, String username) {
+        super(writerId);
         this.vmId = vmId;
         this.vmPid = vmPid;
         this.startTime = startTime;
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -222,7 +222,6 @@
         when(delegateStorage.createRemove(any(Category.class))).thenReturn(remove);
         expectedFile = mock(InputStream.class);
         when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile);
-        when(delegateStorage.getAgentId()).thenReturn("huzzah");
         queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor);
     }
 
@@ -327,31 +326,6 @@
     }
 
     @Test
-    public void testSetAgentId() {
-        UUID id = new UUID(123, 456);
-
-        queuedStorage.setAgentId(id);
-
-        verifyZeroInteractions(delegateStorage);
-        Runnable task = executor.getTask();
-        task.run();
-        verify(delegateStorage).setAgentId(id);
-        
-        assertNull(fileExecutor.getTask());
-    }
-
-    @Test
-    public void testGetAgentId() {
-        String agentId = queuedStorage.getAgentId();
-
-        verify(delegateStorage).getAgentId();
-        assertEquals("huzzah", agentId);
-
-        assertNull(executor.getTask());
-        assertNull(fileExecutor.getTask());
-    }
-
-    @Test
     public void testRegisterCategory() {
 
         Category<?> category = mock(Category.class);
@@ -413,18 +387,6 @@
         long shutDownTime = -1;
 
         @Override
-        public void setAgentId(UUID id) {
-            // not implemented
-            throw new AssertionError();
-        }
-
-        @Override
-        public String getAgentId() {
-            // not implementes
-            throw new AssertionError();
-        }
-
-        @Override
         public void registerCategory(Category<?> category) {
             // not implemented
             throw new AssertionError();
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -38,13 +38,13 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
@@ -67,10 +67,13 @@
 
         activator.start(context);
 
-        assertEquals(0, context.getAllServices().size());
+        // WriterID should get registered unconditionally
+        assertEquals("At least WriterID service must be registered", 1, context.getAllServices().size());
         assertEquals(1, context.getServiceListeners().size());
 
         activator.stop(context);
+        assertEquals(0, context.getAllServices().size());
+        assertEquals(0, context.getServiceListeners().size());
     }
 
     @Test
@@ -84,6 +87,7 @@
 
         activator.start(context);
 
+        assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
         assertTrue(context.isServiceRegistered(HostInfoDAO.class.getName(), HostInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
@@ -93,6 +97,7 @@
         activator.stop(context);
 
         assertEquals(0, context.getServiceListeners().size());
+        
         assertEquals(1, context.getAllServices().size());
     }
 
@@ -114,6 +119,7 @@
         assertFalse(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertFalse(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertFalse(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
+        assertFalse(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
         
         assertEquals(0, context.getServiceListeners().size());
         assertEquals(1, context.getAllServices().size());
@@ -135,6 +141,7 @@
         assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
+        assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
 
         activator.stop(context);
         
@@ -148,6 +155,7 @@
         assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
+        assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
 
         activator.stop(context);
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -78,15 +78,13 @@
 
     @Before
     public void setUp() {
-        agentInfo1 = new AgentInformation();
-        agentInfo1.setAgentId("1234");
+        agentInfo1 = new AgentInformation("1234");
         agentInfo1.setAlive(true);
         agentInfo1.setConfigListenAddress("foobar:666");
         agentInfo1.setStartTime(100);
         agentInfo1.setStopTime(10);
 
-        agent1 = new AgentInformation();
-        agent1.setAgentId("1234");
+        agent1 = new AgentInformation("1234");
         agent1.setAlive(true);
         agent1.setConfigListenAddress("foobar:666");
         agent1.setStartTime(100);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -79,7 +79,7 @@
     @Before
     public void setUp() {
 
-        backendInfo1 = new BackendInformation();
+        backendInfo1 = new BackendInformation("foo-agent1");
 
         backendInfo1.setName("backend-name");
         backendInfo1.setDescription("description");
@@ -88,7 +88,7 @@
         backendInfo1.setPids(new int[] { -1, 0, 1});
         backendInfo1.setOrderValue(100);
 
-        backend1 = new BackendInformation();
+        backend1 = new BackendInformation("foo-agent2");
         backend1.setName("backend-name");
         backend1.setDescription("description");
         backend1.setActive(true);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -119,7 +119,7 @@
         PreparedStatement<HostInfo> prepared = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
         when(storage.prepareStatement(anyDescriptor())).thenReturn(prepared);
 
-        HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
+        HostInfo info = new HostInfo("foo-agent", HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         @SuppressWarnings("unchecked")
         Cursor<HostInfo> cursor = (Cursor<HostInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
@@ -154,7 +154,7 @@
     }
 
     private Storage setupStorageForSingleHost() throws DescriptorParsingException, StatementExecutionException {
-        HostInfo hostConfig = new HostInfo("fluffhost1", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
+        HostInfo hostConfig = new HostInfo("foo-agent", "fluffhost1", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         hostConfig.setAgentId("123");
 
         @SuppressWarnings("unchecked")
@@ -180,20 +180,16 @@
         Collection<HostRef> hosts = hostsDAO.getHosts();
 
         assertEquals(3, hosts.size());
-        assertTrue(hosts.contains(new HostRef("123", "fluffhost1")));
-        assertTrue(hosts.contains(new HostRef("456", "fluffhost2")));
-        assertTrue(hosts.contains(new HostRef("789", "fluffhost3")));
+        assertTrue(hosts.contains(new HostRef("foo-agent-123", "fluffhost1")));
+        assertTrue(hosts.contains(new HostRef("foo-agent-456", "fluffhost2")));
+        assertTrue(hosts.contains(new HostRef("foo-agent-789", "fluffhost3")));
     }
 
     private Storage setupStorageFor3Hosts() throws DescriptorParsingException, StatementExecutionException {
 
-        HostInfo hostConfig1 = new HostInfo("fluffhost1", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        hostConfig1.setAgentId("123");
-        HostInfo hostConfig2 = new HostInfo("fluffhost2", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        hostConfig2.setAgentId("456");
-        HostInfo hostConfig3 = new HostInfo("fluffhost3", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        hostConfig3.setAgentId("789");
-
+        HostInfo hostConfig1 = new HostInfo("foo-agent-123", "fluffhost1", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
+        HostInfo hostConfig2 = new HostInfo("foo-agent-456", "fluffhost2", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
+        HostInfo hostConfig3 = new HostInfo("foo-agent-789", "fluffhost3", OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
 
         @SuppressWarnings("unchecked")
         Cursor<HostInfo> cursor = (Cursor<HostInfo>) mock(Cursor.class);
@@ -218,7 +214,7 @@
 
         AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
 
-        HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
+        HostInfo info = new HostInfo("foo-agent", HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
         HostInfoDAO dao = new HostInfoDAOImpl(storage, agentInfo);
         dao.putHostInfo(info);
 
@@ -287,8 +283,7 @@
         
         // agents
 
-        AgentInformation agentInfo1 = new AgentInformation();
-        agentInfo1.setAgentId("123");
+        AgentInformation agentInfo1 = new AgentInformation("123");
         agentInfo1.setAlive(true);
         
         // hosts
@@ -327,8 +322,7 @@
         
         // agents
 
-        AgentInformation agentInfo1 = new AgentInformation();
-        agentInfo1.setAgentId("123");
+        AgentInformation agentInfo1 = new AgentInformation("123");
         agentInfo1.setAlive(true);
         
         // cursor
@@ -377,16 +371,13 @@
             throws DescriptorParsingException, StatementExecutionException {
         
         // agents
-        AgentInformation agentInfo1 = new AgentInformation();
-        agentInfo1.setAgentId("123");
+        AgentInformation agentInfo1 = new AgentInformation("123");
         agentInfo1.setAlive(true);
 
-        AgentInformation agentInfo2 = new AgentInformation();
-        agentInfo2.setAgentId("456");
+        AgentInformation agentInfo2 = new AgentInformation("456");
         agentInfo2.setAlive(true);
 
-        AgentInformation agentInfo3 = new AgentInformation();
-        agentInfo3.setAgentId("678");
+        AgentInformation agentInfo3 = new AgentInformation("678");
         agentInfo3.setAlive(true);
         
         // hosts
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -37,7 +37,6 @@
 package com.redhat.thermostat.storage.internal.dao;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
@@ -93,7 +92,7 @@
     @Test
     public void testGetNetworkInterfaces() throws DescriptorParsingException, StatementExecutionException {
 
-        NetworkInterfaceInfo niInfo = new NetworkInterfaceInfo(INTERFACE_NAME);
+        NetworkInterfaceInfo niInfo = new NetworkInterfaceInfo("foo-agent", INTERFACE_NAME);
         niInfo.setIp4Addr(IPV4_ADDR);
         niInfo.setIp6Addr(IPV6_ADDR);
 
@@ -136,34 +135,15 @@
     @Test
     public void testPutNetworkInterfaceInfo() {
         String agentId = "fooAgent";
-        doTestPutNetworkInerfaceInfo(false, agentId);
-    }
-    
-    @Test
-    public void testPutNetworkInterfaceInfoWithoutAgentIdInInfo() {
-        String agentId = "fooStorageAgentId";
-        doTestPutNetworkInerfaceInfo(true, agentId);
-    }
-    
-    private void doTestPutNetworkInerfaceInfo(boolean agentIdFromStorage, String agentId) {
         Storage storage = mock(Storage.class);
         @SuppressWarnings("unchecked")
         Replace<NetworkInterfaceInfo> replace = mock(Replace.class);
         when(storage.createReplace(eq(NetworkInterfaceInfoDAO.networkInfoCategory))).thenReturn(replace);
-        if (agentIdFromStorage) {
-            when(storage.getAgentId()).thenReturn(agentId);
-        }
 
-        NetworkInterfaceInfo info = new NetworkInterfaceInfo(INTERFACE_NAME);
+        NetworkInterfaceInfo info = new NetworkInterfaceInfo("foo-agent", INTERFACE_NAME);
         info.setIp4Addr(IPV4_ADDR);
         info.setIp6Addr(IPV6_ADDR);
-        if (!agentIdFromStorage) {
-            info.setAgentId(agentId);
-        } else {
-            // case where agentId gets replaced by the DAO
-            // with the one set for storage.
-            assertNull(info.getAgentId());
-        }
+        info.setAgentId(agentId);
         ExpressionFactory factory = new ExpressionFactory();
         Expression left = factory.equalTo(Key.AGENT_ID, agentId);
         Expression right = factory.equalTo(NetworkInterfaceInfoDAO.ifaceKey, INTERFACE_NAME);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -155,7 +155,7 @@
         @SuppressWarnings("unchecked")
         PreparedStatement<VmInfo> stmt = (PreparedStatement<VmInfo>) mock(PreparedStatement.class);
         when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
-        VmInfo expected = new VmInfo(vmId, vmPid, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs, uid, username);
+        VmInfo expected = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs, uid, username);
         @SuppressWarnings("unchecked")
         Cursor<VmInfo> cursor = (Cursor<VmInfo>) mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
@@ -319,7 +319,7 @@
         Add<VmInfo> add = mock(Add.class);
         when(storage.createAdd(eq(VmInfoDAO.vmInfoCategory))).thenReturn(add);
 
-        VmInfo info = new VmInfo(vmId, vmPid, startTime, stopTime, jVersion, jHome,
+        VmInfo info = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome,
                 mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs,
                 props, env, libs, uid, username);
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/model/BackendInformationTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/model/BackendInformationTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.storage.model;
 
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
 import java.util.Map;
 
@@ -48,7 +49,7 @@
 
     @Test
     public void testConfigurationNotNull() {
-        BackendInformation backendInfo = new BackendInformation();
+        BackendInformation backendInfo = new BackendInformation("foo-agent");
         Map<String,String> config = backendInfo.getConfiguration();
         assertNotNull(config);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/model/BasePojoTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * 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.storage.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+public class BasePojoTest {
+
+    @Test
+    public void testDefaultConstructorMissing() {
+        // Developers are advised to always use the one-arg constructor
+        // which sets the writer-ID. The no-arg constructor in the extending
+        // class should be provided there directly. Not in BasePojo. This is
+        // to assist devs via the compiler for missing writer-ID properties. 
+        try {
+            BasePojo.class.newInstance();
+            fail("Are you sure you want to provide a no-arg constructor in BasePojo?");
+        } catch (Exception e) {
+            // pass
+        }
+    }
+    
+    @Test
+    public void testWriterIdConstructor() {
+        BasePojo pojo = new BasePojo("foo-agent");
+        assertEquals("foo-agent", pojo.getAgentId());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java	Mon Sep 02 11:36:26 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.storage.model;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.Test;
+
+public class PojoModelInstantiationTest {
+    
+    private static final Class<?>[] CLASSES_LIST = new Class[] {
+        AgentInformation.class,
+        BackendInformation.class,
+        NetworkInterfaceInfo.class,
+        VmInfo.class,
+        HostInfo.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/storage/core/src/test/java/com/redhat/thermostat/storage/model/TimeStampedPojoCorrelatorTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/model/TimeStampedPojoCorrelatorTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -56,6 +56,7 @@
         private long timestamp;
 
         private TestTimeStampedPojo(long timestamp) {
+            super(null);
             this.timestamp = timestamp;
         }
 
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Mon Sep 02 11:36:26 2013 +0200
@@ -41,7 +41,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 
 import com.mongodb.BasicDBObject;
@@ -169,16 +168,16 @@
         
     }
 
-    private MongoConnection conn;
+    private final MongoConnection conn;
+    private final Map<String, DBCollection> collectionCache = new HashMap<String, DBCollection>();
+    private final CountDownLatch connectedLatch;
     private DB db = null;
-    private Map<String, DBCollection> collectionCache = new HashMap<String, DBCollection>();
-    private CountDownLatch connectedLatch;
-    private UUID agentId;
 
     // For testing only
     MongoStorage(DB db, CountDownLatch latch) {
         this.db = db;
         this.connectedLatch = latch;
+        this.conn = null;
     }
     
     public MongoStorage(StartupConfiguration conf) {
@@ -219,16 +218,6 @@
     }
 
     @Override
-    public void setAgentId(UUID agentId) {
-        this.agentId = agentId;
-    }
-
-    @Override
-    public String getAgentId() {
-        return agentId.toString();
-    }
-
-    @Override
     public <T extends Pojo> Add<T> createAdd(Category<T> into) {
         MongoAdd<T> add = new MongoAdd<>(into);
         return add;
@@ -264,7 +253,8 @@
         MongoPojoConverter converter = new MongoPojoConverter();
         DBObject toInsert = converter.convertPojoToMongo(pojo);
         if (toInsert.get(Key.AGENT_ID.getName()) == null) {
-            toInsert.put(Key.AGENT_ID.getName(), getAgentId());
+            // FIXME: Remove
+            throw new AssertionError("agentID must be set");
         }
         return toInsert;
     }
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -61,6 +61,11 @@
 
     @Entity
     public static class TestClass extends BasePojo {
+        
+        public TestClass() {
+            super(null);
+        }
+        
         private String key1;
         private String key2;
         private String key3;
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -42,6 +42,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -56,7 +57,6 @@
 import java.lang.reflect.Field;
 import java.util.LinkedHashSet;
 import java.util.Set;
-import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 
 import org.junit.After;
@@ -111,6 +111,10 @@
 
     @Entity
     public static class TestClass extends BasePojo {
+        
+        public TestClass() {
+            super(null);
+        }
         private String key1;
         private String key2;
         private String key3;
@@ -383,17 +387,28 @@
     }
 
     @Test
-    public void verifyPutChunkUsesCorrectGlobalAgent() throws Exception {
+    public void verifyPutChunkDoesNotUseGlobalAgent() throws Exception {
         MongoStorage storage = makeStorage();
-        storage.setAgentId(new UUID(1, 2));
         TestClass pojo = new TestClass();
         Add add = storage.createAdd(testCategory);
         add.setPojo(pojo);
-        add.apply();
-        ArgumentCaptor<DBObject> dbobj = ArgumentCaptor.forClass(DBObject.class);
-        verify(testCollection).insert(dbobj.capture());
-        DBObject val = dbobj.getValue();
-        assertEquals(new UUID(1, 2).toString(), val.get("agentId"));
+        try {
+            add.apply();
+            fail("We do not allow null agentId");
+        } catch (AssertionError e) {
+            // pass
+        }
+        Replace replace = storage.createReplace(testCategory);
+        ExpressionFactory factory = new ExpressionFactory();
+        Expression whereExp = factory.equalTo(Key.AGENT_ID, "foobar");
+        replace.setPojo(pojo);
+        replace.where(whereExp);
+        try {
+            replace.apply();
+            fail("We do not allow null agentId");
+        } catch (AssertionError e) {
+            // pass
+        }
     }
 
     @Test
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/HostInfoBuilder.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/HostInfoBuilder.java	Mon Sep 02 11:36:26 2013 +0200
@@ -46,6 +46,7 @@
 import com.redhat.thermostat.common.Size;
 import com.redhat.thermostat.common.Size.Unit;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.HostInfo;
 import com.redhat.thermostat.utils.ProcDataSource;
 import com.redhat.thermostat.utils.hostname.HostName;
@@ -85,9 +86,11 @@
     }
 
     private final ProcDataSource dataSource;
+    private final WriterID writerId;
 
-    public HostInfoBuilder(ProcDataSource dataSource) {
+    public HostInfoBuilder(ProcDataSource dataSource, WriterID writerId) {
         this.dataSource = dataSource;
+        this.writerId = writerId;
     }
 
     public HostInfo build() {
@@ -96,8 +99,8 @@
         HostMemoryInfo memoryInfo = getMemoryInfo();
         long totalMemorySize = (long) memoryInfo.totalMemory.convertTo(Unit.B).getValue();
         HostOsInfo osInfo = getOsInfo();
-
-        return new HostInfo(hostname, osInfo.distribution, osInfo.kernel, cpuInfo.model, cpuInfo.count, totalMemorySize);
+        String wId = writerId.getWriterID();
+        return new HostInfo(wId, hostname, osInfo.distribution, osInfo.kernel, cpuInfo.model, cpuInfo.count, totalMemorySize);
     }
 
     HostCpuInfo getCpuInfo() {
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Mon Sep 02 11:36:26 2013 +0200
@@ -56,6 +56,7 @@
 import com.redhat.thermostat.backend.system.ProcessUserInfoBuilder.ProcessUserInfo;
 import com.redhat.thermostat.common.Pair;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
 import com.redhat.thermostat.utils.ProcDataSource;
@@ -65,17 +66,16 @@
     private static final Logger logger = LoggingUtils.getLogger(JvmStatHostListener.class);
 
     private final VmInfoDAO vmInfoDAO;
-
+    private final VmStatusChangeNotifier notifier;
+    private final ProcessUserInfoBuilder userInfoBuilder;
+    private final WriterID writerId;
     private Map<Integer, Pair<String, MonitoredVm>> monitoredVms  = new HashMap<>();
-    
-    private VmStatusChangeNotifier notifier;
 
-    private ProcessUserInfoBuilder userInfoBuilder;
-
-    JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier, ProcessUserInfoBuilder userInfoBuilder) {
+    JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier, ProcessUserInfoBuilder userInfoBuilder, WriterID writerId) {
         this.vmInfoDAO = vmInfoDAO;
         this.notifier = notifier;
         this.userInfoBuilder = userInfoBuilder;
+        this.writerId = writerId;
     }
 
     @Override
@@ -141,7 +141,7 @@
         // TODO actually figure out the loaded libraries.
         String[] loadedNativeLibraries = new String[0];
         ProcessUserInfo userInfo = userInfoBuilder.build(vmPid);
-        VmInfo info = new VmInfo(vmId, vmPid, startTime, stopTime,
+        VmInfo info = new VmInfo(writerId.getWriterID(), vmId, vmPid, startTime, stopTime,
                 extractor.getJavaVersion(), extractor.getJavaHome(),
                 extractor.getMainClass(), extractor.getCommandLine(),
                 extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(),
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/NetworkInfoBuilder.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/NetworkInfoBuilder.java	Mon Sep 02 11:36:26 2013 +0200
@@ -49,18 +49,26 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
 public class NetworkInfoBuilder {
 
     private static final Logger logger = LoggingUtils.getLogger(NetworkInfoBuilder.class);
 
-    public static List<NetworkInterfaceInfo> build() {
+    private final WriterID writerId;
+    
+    public NetworkInfoBuilder(WriterID writerId) {
+        this.writerId = writerId;
+    }
+    
+    public List<NetworkInterfaceInfo> build() {
         List<NetworkInterfaceInfo> infos = new ArrayList<NetworkInterfaceInfo>();
+        String wId = writerId.getWriterID();
         try {
             Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
             for (NetworkInterface iface : Collections.list(ifaces)) {
-                NetworkInterfaceInfo info = new NetworkInterfaceInfo(iface.getName());
+                NetworkInterfaceInfo info = new NetworkInterfaceInfo(wId, iface.getName());
                 for (InetAddress addr : Collections.list(iface.getInetAddresses())) {
                     if (addr instanceof Inet4Address) {
                         info.setIp4Addr(addr.getHostAddress());
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Mon Sep 02 11:36:26 2013 +0200
@@ -42,6 +42,8 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.osgi.framework.BundleContext;
+
 import sun.jvmstat.monitor.HostIdentifier;
 import sun.jvmstat.monitor.MonitorException;
 import sun.jvmstat.monitor.MonitoredHost;
@@ -49,6 +51,7 @@
 import com.redhat.thermostat.backend.BaseBackend;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
@@ -71,11 +74,12 @@
     private MonitoredHost host = null;
     private JvmStatHostListener hostListener = null;
 
+    private final NetworkInfoBuilder networkInfoBuilder;
     private final HostInfoBuilder hostInfoBuilder;
 
 
     public SystemBackend(HostInfoDAO hostInfoDAO, NetworkInterfaceInfoDAO netInfoDAO, VmInfoDAO vmInfoDAO,
-            Version version, VmStatusChangeNotifier notifier, UserNameUtil userNameUtil) {
+            Version version, VmStatusChangeNotifier notifier, UserNameUtil userNameUtil, WriterID writerId) {
         super("System Backend",
                 "Gathers basic information from the system",
                 "Red Hat, Inc.",
@@ -84,8 +88,9 @@
         this.networkInterfaces = netInfoDAO;
 
         ProcDataSource source = new ProcDataSource();
-        hostInfoBuilder = new HostInfoBuilder(source);
-        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, new ProcessUserInfoBuilder(source, userNameUtil));
+        hostInfoBuilder = new HostInfoBuilder(source, writerId);
+        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, new ProcessUserInfoBuilder(source, userNameUtil), writerId);
+        networkInfoBuilder = new NetworkInfoBuilder(writerId);
     }
 
     @Override
@@ -103,7 +108,7 @@
         timer.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
-                for (NetworkInterfaceInfo info: NetworkInfoBuilder.build()) {
+                for (NetworkInterfaceInfo info: networkInfoBuilder.build()) {
                     networkInterfaces.putNetworkInterfaceInfo(info);
                 }
             }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Mon Sep 02 11:36:26 2013 +0200
@@ -49,6 +49,7 @@
 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.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
@@ -73,7 +74,8 @@
                 HostInfoDAO.class,
                 NetworkInterfaceInfoDAO.class,
                 VmInfoDAO.class,
-                UserNameUtil.class
+                UserNameUtil.class,
+                WriterID.class // system backend uses it
         };
         tracker = new MultipleServiceTracker(context, deps, new Action() {
             @Override
@@ -84,7 +86,8 @@
                 VmInfoDAO vmInfoDAO = (VmInfoDAO) services.get(VmInfoDAO.class.getName());
                 UserNameUtil userNameUtil = (UserNameUtil) services.get(UserNameUtil.class.getName());
                 Version version = new Version(context.getBundle());
-                backend = new SystemBackend(hostInfoDAO, netInfoDAO, vmInfoDAO, version, notifier, userNameUtil);
+                WriterID id = (WriterID) services.get(WriterID.class.getName());
+                backend = new SystemBackend(hostInfoDAO, netInfoDAO, vmInfoDAO, version, notifier, userNameUtil, id);
                 reg = context.registerService(Backend.class, backend, null);
             }
             
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/HostInfoBuilderTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/HostInfoBuilderTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -46,22 +46,30 @@
 import java.io.StringReader;
 import java.net.InetAddress;
 
+import org.junit.Before;
 import org.junit.Test;
 
 import com.redhat.thermostat.backend.system.HostInfoBuilder.HostCpuInfo;
 import com.redhat.thermostat.backend.system.HostInfoBuilder.HostMemoryInfo;
 import com.redhat.thermostat.backend.system.HostInfoBuilder.HostOsInfo;
 import com.redhat.thermostat.common.Size;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.HostInfo;
 import com.redhat.thermostat.utils.ProcDataSource;
 
 public class HostInfoBuilderTest {
 
     final int KILOBYTES_TO_BYTES = 1024;
+    private WriterID writerId;
+    
+    @Before
+    public void setup() {
+        writerId = mock(WriterID.class);
+    }
 
     @Test
     public void testSimpleBuild() {
-        HostInfo info = new HostInfoBuilder(new ProcDataSource()).build();
+        HostInfo info = new HostInfoBuilder(new ProcDataSource(), writerId).build();
         assertNotNull(info);
     }
 
@@ -78,7 +86,7 @@
         ProcDataSource dataSource = mock(ProcDataSource.class);
         when(dataSource.getCpuInfoReader()).thenReturn(cpuInfoReader);
 
-        HostCpuInfo cpuInfo = new HostInfoBuilder(dataSource).getCpuInfo();
+        HostCpuInfo cpuInfo = new HostInfoBuilder(dataSource, writerId).getCpuInfo();
         assertEquals(2, cpuInfo.count);
         assertEquals("Test Model", cpuInfo.model);
         verify(dataSource).getCpuInfoReader();
@@ -93,7 +101,7 @@
         ProcDataSource dataSource = mock(ProcDataSource.class);
         when(dataSource.getMemInfoReader()).thenReturn(memoryInfoReader);
 
-        HostMemoryInfo memoryInfo = new HostInfoBuilder(dataSource).getMemoryInfo();
+        HostMemoryInfo memoryInfo = new HostInfoBuilder(dataSource, writerId).getMemoryInfo();
         assertNotNull(memoryInfo);
         assertEquals(Size.bytes(12345 * KILOBYTES_TO_BYTES), memoryInfo.totalMemory);
         verify(dataSource).getMemInfoReader();
@@ -104,7 +112,7 @@
     public void testOsInfo() {
         DistributionInformation distroInfo = new DistributionInformation("distro-name", "distro-version");
         ProcDataSource dataSource = mock(ProcDataSource.class);
-        HostOsInfo osInfo = new HostInfoBuilder(dataSource).getOsInfo(distroInfo);
+        HostOsInfo osInfo = new HostInfoBuilder(dataSource, writerId).getOsInfo(distroInfo);
         assertEquals("distro-name distro-version", osInfo.distribution);
         assertEquals(System.getProperty("os.name") + " " + System.getProperty("os.version"), osInfo.kernel);
     }
@@ -117,7 +125,7 @@
 
         ProcDataSource dataSource = mock(ProcDataSource.class);
 
-        String name = new HostInfoBuilder(dataSource).getHostName(address);
+        String name = new HostInfoBuilder(dataSource, writerId).getHostName(address);
         assertEquals("test-hostname", name);
     }
 
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/JvmStatHostListenerTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/JvmStatHostListenerTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -70,6 +70,7 @@
 
 import com.redhat.thermostat.agent.VmStatusListener.Status;
 import com.redhat.thermostat.backend.system.ProcessUserInfoBuilder.ProcessUserInfo;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
 
@@ -103,7 +104,8 @@
         ProcessUserInfo userInfo = new ProcessUserInfo(INFO_VMUSERID, INFO_VMUSERNAME);
         when(userInfoBuilder.build(any(int.class))).thenReturn(userInfo);
 
-        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder);
+        WriterID id = mock(WriterID.class);
+        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id);
         
         host = mock(MonitoredHost.class);
         HostIdentifier hostId = mock(HostIdentifier.class);
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/NetworkInfoBuilderTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/NetworkInfoBuilderTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -38,11 +38,13 @@
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
 import java.util.List;
 
 import org.junit.Test;
 
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
 public class NetworkInfoBuilderTest {
@@ -50,7 +52,10 @@
     @Test
     public void testBuilder() {
 
-        List<NetworkInterfaceInfo> info = NetworkInfoBuilder.build();
+        WriterID id = mock(WriterID.class);
+        
+        NetworkInfoBuilder builder = new NetworkInfoBuilder(id);
+        List<NetworkInterfaceInfo> info = builder.build();
         assertNotNull(info);
         for (NetworkInterfaceInfo iface: info) {
             assertNotNull(iface);
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -46,6 +46,7 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
@@ -68,7 +69,8 @@
         VmStatusChangeNotifier notifier = mock(VmStatusChangeNotifier.class);
         UserNameUtil util = mock(UserNameUtil.class);
 
-        b = new SystemBackend(hDAO, nDAO, vmInfoDAO, version, notifier, util);
+        WriterID id = mock(WriterID.class);
+        b = new SystemBackend(hDAO, nDAO, vmInfoDAO, version, notifier, util, id);
     }
 
     @Test
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Mon Sep 02 11:36:26 2013 +0200
@@ -53,7 +53,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -372,7 +371,6 @@
     }
 
     private String endpoint;
-    private UUID agentId;
 
     private Map<Category<?>, Integer> categoryIds;
     private Gson gson;
@@ -590,11 +588,6 @@
     }
 
     @Override
-    public String getAgentId() {
-        return agentId.toString();
-    }
-
-    @Override
     public Connection getConnection() {
         return conn;
     }
@@ -651,7 +644,7 @@
     
     private int addImpl(final WebAdd<?> add) throws StorageException {
         Pojo pojo = add.getPojo();
-        maybeAddAgentId(pojo);
+        checkAgentIdIsSet(pojo);
         NameValuePair pojoParam = new BasicNameValuePair("pojo",
                 gson.toJson(pojo));
         NameValuePair addParam = new BasicNameValuePair("add",
@@ -663,7 +656,7 @@
 
     private int replaceImpl(final WebReplace<?> replace) throws StorageException {
         Pojo pojo = replace.getPojo();
-        maybeAddAgentId(pojo);
+        checkAgentIdIsSet(pojo);
         NameValuePair replaceParam = new BasicNameValuePair("replace",
                 gson.toJson(replace));
         NameValuePair pojoParam = new BasicNameValuePair("pojo",
@@ -673,10 +666,10 @@
         return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
     }
 
-    private void maybeAddAgentId(final Pojo pojo) throws AssertionError {
+    private void checkAgentIdIsSet(final Pojo pojo) throws AssertionError {
         try {
             if (BeanUtils.getProperty(pojo, Key.AGENT_ID.getName()) == null) {
-                BeanUtils.setProperty(pojo, Key.AGENT_ID.getName(), getAgentId());
+                throw new AssertionError("agentId must be set!");
             }
         } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
             throw new AssertionError("Pojo needs to have an agentId property");
@@ -691,11 +684,6 @@
         return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
     }
 
-    @Override
-    public void setAgentId(UUID agentId) {
-        this.agentId = agentId;
-    }
-
     private int updatePojo(Update<?> update) throws StorageException {
         WebUpdate<?> webUp = (WebUpdate<?>) update;
         List<WebUpdate.UpdateValue> updateValues = webUp.getUpdates();
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/TestObj.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/TestObj.java	Mon Sep 02 11:36:26 2013 +0200
@@ -44,6 +44,9 @@
 @Entity
 public class TestObj extends BasePojo {
 
+    public TestObj() {
+        super(null);
+    }
     
     private String property1;
 
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -186,7 +186,6 @@
         };
         storage = new WebStorage(config);
         storage.setEndpoint("http://localhost:" + port + "/");
-        storage.setAgentId(new UUID(123, 456));
         headers = new HashMap<>();
         registerCategory();
         factory = new ExpressionFactory();
@@ -395,12 +394,10 @@
     @Test
     public void testAdd() throws IOException, JsonSyntaxException, ClassNotFoundException {
 
+        UUID agentId = new UUID(1, 2);
         TestObj obj = new TestObj();
         obj.setProperty1("fluff");
-
-        // We need an agentId, so that we can check automatic insert of agentId.
-        UUID agentId = new UUID(1, 2);
-        storage.setAgentId(agentId);
+        obj.setAgentId(agentId.toString());
 
         Add<TestObj> add = storage.createAdd(category);
         add.setPojo(obj);
@@ -424,21 +421,17 @@
         assertEquals(2, parts.length);
         assertEquals("pojo", parts[0]);
         Object resultObj = gson.fromJson(parts[1], TestObj.class);
-
-        // Set agentId on expected object, because we expect WebStorage to insert it for us.
-        obj.setAgentId(agentId.toString());
         assertEquals(obj, resultObj);
     }
 
     @Test
     public void testReplace() throws IOException, JsonSyntaxException, ClassNotFoundException {
 
-        TestObj obj = new TestObj();
-        obj.setProperty1("fluff");
-
         // We need an agentId, so that we can check automatic insert of agentId.
         UUID agentId = new UUID(1, 2);
-        storage.setAgentId(agentId);
+        TestObj obj = new TestObj();
+        obj.setAgentId(agentId.toString());
+        obj.setProperty1("fluff");
 
         Replace<TestObj> replace = storage.createReplace(category);
         Expression expr = new ExpressionFactory().equalTo(key1, "fluff");
@@ -468,9 +461,6 @@
         assertEquals(2, parts.length);
         assertEquals("pojo", parts[0]);
         Object resultObj = gson.fromJson(parts[1], TestObj.class);
-
-        // Set agentId on expected object, because we expect WebStorage to insert it for us.
-        obj.setAgentId(agentId.toString());
         assertEquals(obj, resultObj);
     }
 
@@ -755,7 +745,6 @@
         };
         storage = new WebStorage(config, client, connManager);
         storage.setEndpoint("http://localhost:" + port + "/");
-        storage.setAgentId(new UUID(123, 456));
         
         CountDownLatch latch = new CountDownLatch(1);
         MyListener listener = new MyListener(latch);
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/ThermostatGSONConverterTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/web/common/src/test/java/com/redhat/thermostat/web/common/ThermostatGSONConverterTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -61,8 +61,7 @@
     @Test
     public void canSerializeDeserializeBasic() {
         // Our test pojo
-        AgentInformation agentInfo = new AgentInformation();
-        agentInfo.setAgentId("testing");
+        AgentInformation agentInfo = new AgentInformation("testing");
         agentInfo.setAlive(true);
         
         String jsonStr = gson.toJson(agentInfo);
@@ -76,8 +75,7 @@
     @Test
     public void canSerializeDeserializeArray() {
         // Our test pojo
-        AgentInformation agentInfo = new AgentInformation();
-        agentInfo.setAgentId("testing");
+        AgentInformation agentInfo = new AgentInformation("testing");
         agentInfo.setAlive(true);
         AgentInformation[] agentInfos = new AgentInformation[] {
                 agentInfo
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseSerializerTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseSerializerTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -66,8 +66,7 @@
     @Test
     public void canSerializeBasic() {
         // Our test pojo
-        AgentInformation agentInfo = new AgentInformation();
-        agentInfo.setAgentId("testing");
+        AgentInformation agentInfo = new AgentInformation("testing");
         agentInfo.setAlive(false);
         AgentInformation[] resultList = new AgentInformation[] {
                 agentInfo
@@ -101,8 +100,7 @@
     @Test
     public void canSerializeAndDeserializeBasic() {
         // Our test pojo
-        AgentInformation agentInfo = new AgentInformation();
-        agentInfo.setAgentId("testing");
+        AgentInformation agentInfo = new AgentInformation("testing");
         agentInfo.setAlive(false);
         AgentInformation[] resultList = new AgentInformation[] {
                 agentInfo
@@ -132,8 +130,7 @@
     @Test
     public void canSerializeAndDeserializeVariousPojos() {
         // Our test pojo
-        AgentInformation agentInfo = new AgentInformation();
-        agentInfo.setAgentId("testing");
+        AgentInformation agentInfo = new AgentInformation("testing");
         agentInfo.setAlive(false);
         AgentInformation[] resultList = new AgentInformation[] {
                 agentInfo
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Thu Sep 05 15:58:29 2013 -0400
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Mon Sep 02 11:36:26 2013 +0200
@@ -151,6 +151,11 @@
 
     @Entity
     public static class TestClass extends BasePojo {
+        
+        public TestClass() {
+            super(null);
+        }
+        
         private String key1;
         private int key2;
         @Persist