changeset 697:d552470b531b

Make web service the default (for now). Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-October/003744.html
author Roman Kennke <rkennke@redhat.com>
date Wed, 17 Oct 2012 19:08:13 +0200
parents 1c430d80ed06
children a31b9467af11 0daa5cf25aec
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java agent/core/src/main/java/com/redhat/thermostat/backend/sample/SampleBackend.java agent/core/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java agent/core/src/test/java/com/redhat/thermostat/backend/BackendRegistryTest.java agent/core/src/test/java/com/redhat/thermostat/backend/sample/SampleBackendTest.java agent/core/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java common/core/pom.xml common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/model/AgentInformation.java common/core/src/main/java/com/redhat/thermostat/common/model/BackendInformation.java common/core/src/main/java/com/redhat/thermostat/common/model/BasePojo.java common/core/src/main/java/com/redhat/thermostat/common/model/CpuStat.java common/core/src/main/java/com/redhat/thermostat/common/model/HeapInfo.java common/core/src/main/java/com/redhat/thermostat/common/model/HostInfo.java common/core/src/main/java/com/redhat/thermostat/common/model/MemoryStat.java common/core/src/main/java/com/redhat/thermostat/common/model/NetworkInterfaceInfo.java common/core/src/main/java/com/redhat/thermostat/common/model/Pojo.java common/core/src/main/java/com/redhat/thermostat/common/model/VmClassStat.java common/core/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java common/core/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java common/core/src/main/java/com/redhat/thermostat/common/model/VmInfo.java common/core/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java common/core/src/main/java/com/redhat/thermostat/common/storage/AbstractQuery.java common/core/src/main/java/com/redhat/thermostat/common/storage/Category.java common/core/src/main/java/com/redhat/thermostat/common/storage/Key.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoQuery.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorageProvider.java common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/model/TimeStampedPojoCorrelatorTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/CategoryTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoCursorTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoQueryTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/StorageTest.java distribution/config/commands/gui.properties distribution/config/commands/service.properties distribution/config/osgi-export.properties distribution/pom.xml thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java web/client/pom.xml web/client/src/main/java/com/redhat/thermostat/web/client/Activator.java web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/RESTStorageTest.java web/client/src/test/java/com/redhat/thermostat/web/client/TestObj.java web/common/pom.xml web/common/src/main/java/com/redhat/thermostat/web/common/RESTQuery.java web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java web/common/src/test/java/RESTQueryTest.java web/server/pom.xml web/server/src/main/java/com/redhat/thermostat/web/server/Activator.java web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java
diffstat 73 files changed, 793 insertions(+), 395 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java	Wed Oct 17 19:08:13 2012 +0200
@@ -209,7 +209,13 @@
         @Override
         public void handle(Signal arg0) {
             configServer.stopListening();
-            agent.stop();
+            try {
+                agent.stop();
+            } catch (Exception ex) {
+                // We don't want any exception to hold back the signal handler, otherwise
+                // there will be no way to actually stop Thermostat.
+                ex.printStackTrace();
+            }
             logger.fine("Agent stopped.");       
             shutdownLatch.countDown();
         }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java	Wed Oct 17 19:08:13 2012 +0200
@@ -36,14 +36,12 @@
 
 package com.redhat.thermostat.backend;
 
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 
 import com.redhat.thermostat.common.LaunchException;
 import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Storage;
 
 /**
@@ -88,16 +86,11 @@
     public final void setDAOFactory(DAOFactory df) {
         this.df = df;
         this.storage = df.getStorage();
-        for (Category cat : getCategories()) {
-            storage.registerCategory(cat);
-        }
         setDAOFactoryAction();
     }
 
     protected abstract void setDAOFactoryAction();
 
-    protected abstract Collection<Category> getCategories();
-
     /**
      * Set the named configuration to the given value.
      * The basic special properties {@code name}, {@code version} and
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/sample/SampleBackend.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/sample/SampleBackend.java	Wed Oct 17 19:08:13 2012 +0200
@@ -36,16 +36,13 @@
 
 package com.redhat.thermostat.backend.sample;
 
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.backend.Backend;
-import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 /**
@@ -121,11 +118,6 @@
     }
 
     @Override
-    protected Collection<Category> getCategories() {
-        return new HashSet<Category>();
-    }
-
-    @Override
     public boolean attachToNewProcessByDefault() {
         return false;
     }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Wed Oct 17 19:08:13 2012 +0200
@@ -81,8 +81,6 @@
     private VmCpuStatDAO vmCpuStats;
     private NetworkInterfaceInfoDAO networkInterfaces;
 
-    private final List<Category> categories = new ArrayList<Category>();
-
     private final Set<Integer> pidsToMonitor = new CopyOnWriteArraySet<Integer>();
 
     private long procCheckInterval = 1000; // TODO make this configurable.
@@ -101,17 +99,6 @@
     public SystemBackend() {
         super();
 
-        // Set up categories that will later be registered.
-        categories.add(CpuStatDAO.cpuStatCategory);
-        categories.add(HostInfoDAO.hostInfoCategory);
-        categories.add(MemoryStatDAO.memoryStatCategory);
-        categories.add(NetworkInterfaceInfoDAO.networkInfoCategory);
-        categories.add(VmClassStatDAO.vmClassStatsCategory);
-        categories.add(VmCpuStatDAO.vmCpuStatCategory);
-        categories.add(VmGcStatDAO.vmGcStatCategory);
-        categories.add(VmInfoDAO.vmInfoCategory);
-        categories.add(VmMemoryStatDAO.vmMemoryStatsCategory);
-
         Clock clock = new SystemClock();
         ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(new ProcDataSource());
         long ticksPerSecond = SysConf.getClockTicksPerSecond();
@@ -227,11 +214,6 @@
     }
 
     @Override
-    protected Collection<Category> getCategories() {
-        return Collections.unmodifiableCollection(categories);
-    }
-
-    @Override
     public boolean attachToNewProcessByDefault() {
         return true;
     }
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/BackendRegistryTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/BackendRegistryTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -43,8 +43,6 @@
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
@@ -56,7 +54,6 @@
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.config.InvalidConfigurationException;
 import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Storage;
 
 public class BackendRegistryTest {
@@ -67,10 +64,6 @@
         }
 
         @Override
-        protected Collection<Category> getCategories() {
-            return Collections.emptyList();
-        }
-        @Override
         public String getConfigurationValue(String key) {
             return null;
         }
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/sample/SampleBackendTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/sample/SampleBackendTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -41,13 +41,9 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.util.Collection;
-
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.common.storage.Category;
-
 public class SampleBackendTest {
 
     private SampleBackend b;
@@ -89,12 +85,6 @@
     }
 
     @Test
-    public void testCategoriesAreSane() {
-        Collection<Category> categories = b.getCategories();
-        assertEquals(0, categories.size());
-    }
-
-    @Test
     public void testDefaultConfiguration() {
         assertTrue(b.getConfigurationMap().isEmpty());
         assertTrue(b.getConfigurationValue("foo") == null);
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/agent/core/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -41,8 +41,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.Collection;
-
 import org.junit.Before;
 import org.junit.Test;
 
@@ -51,12 +49,7 @@
 import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.MemoryStatDAO;
 import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.common.dao.VmClassStatDAO;
 import com.redhat.thermostat.common.dao.VmCpuStatDAO;
-import com.redhat.thermostat.common.dao.VmGcStatDAO;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Storage;
 
 public class SystemBackendTest {
@@ -105,19 +98,4 @@
         assertFalse(b.isActive());
     }
 
-    @Test
-    public void testCategoriesAreSane() {
-        Collection<Category> categories = b.getCategories();
-
-        assertTrue(categories.contains(CpuStatDAO.cpuStatCategory));
-        assertTrue(categories.contains(HostInfoDAO.hostInfoCategory));
-        assertTrue(categories.contains(MemoryStatDAO.memoryStatCategory));
-        assertTrue(categories.contains(NetworkInterfaceInfoDAO.networkInfoCategory));
-        assertTrue(categories.contains(VmClassStatDAO.vmClassStatsCategory));
-        assertTrue(categories.contains(VmCpuStatDAO.vmCpuStatCategory));
-        assertTrue(categories.contains(VmGcStatDAO.vmGcStatCategory));
-        assertTrue(categories.contains(VmInfoDAO.vmInfoCategory));
-        assertTrue(categories.contains(VmMemoryStatDAO.vmMemoryStatsCategory));
-    }
-
 }
--- a/common/core/pom.xml	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/pom.xml	Wed Oct 17 19:08:13 2012 +0200
@@ -170,6 +170,18 @@
     	<artifactId>thermostat-keyring</artifactId>
     	<version>${project.version}</version>
     </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>8.1.5.v20120716</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>8.1.5.v20120716</version>
+    </dependency>
+
   </dependencies>
 
 </project>
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -54,7 +54,7 @@
 
     public AgentInfoDAOImpl(Storage storage) {
         this.storage = storage;
-        storage.createConnectionKey(CATEGORY);
+        storage.registerCategory(CATEGORY);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -53,7 +53,7 @@
 
     public BackendInfoDAOImpl(Storage storage) {
         this.storage = storage;
-        storage.createConnectionKey(CATEGORY);
+        storage.registerCategory(CATEGORY);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -49,6 +49,7 @@
 
     CpuStatDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(cpuStatCategory);
         this.getter = new HostLatestPojoListGetter<>(storage, cpuStatCategory, CpuStat.class);
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -66,7 +66,7 @@
 
     HeapDAOImpl(Storage storage) {
         this.storage = storage;
-        storage.createConnectionKey(heapInfoCategory);
+        storage.registerCategory(heapInfoCategory);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -57,6 +57,7 @@
     public HostInfoDAOImpl(Storage storage, AgentInfoDAO agentInfo) {
         this.storage = storage;
         this.agentInfoDao = agentInfo;
+        storage.registerCategory(hostInfoCategory);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -49,6 +49,7 @@
 
     MemoryStatDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(memoryStatCategory);
         this.getter = new HostLatestPojoListGetter<>(storage, memoryStatCategory, MemoryStat.class);
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -52,6 +52,7 @@
 
     NetworkInterfaceInfoDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(networkInfoCategory);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -48,6 +48,7 @@
 
     VmClassStatDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(vmClassStatsCategory);
         this.getter = new VmLatestPojoListGetter<>(storage, vmClassStatsCategory, VmClassStat.class);
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -48,6 +48,7 @@
 
     VmCpuStatDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(vmCpuStatCategory);
         this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory, VmCpuStat.class);
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -48,6 +48,7 @@
 
     VmGcStatDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(vmGcStatCategory);
         getter = new VmLatestPojoListGetter<>(storage, vmGcStatCategory, VmGcStat.class);
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -54,6 +54,7 @@
 
     VmInfoDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(vmInfoCategory);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatConverter.java	Wed Oct 17 19:08:13 2012 +0200
@@ -51,6 +51,7 @@
     public Chunk toChunk(VmMemoryStat vmMemStat) {
         Chunk chunk = new Chunk(VmMemoryStatDAO.vmMemoryStatsCategory, false);
 
+        chunk.put(Key.AGENT_ID, vmMemStat.getAgentId());
         chunk.put(Key.VM_ID, vmMemStat.getVmId());
         chunk.put(Key.TIMESTAMP, vmMemStat.getTimeStamp());
 
@@ -176,7 +177,8 @@
         permGen.maxCapacity = space.capacity;
 
         gens.add(permGen);
-
-        return new VmMemoryStat(chunk.get(Key.TIMESTAMP), chunk.get(Key.VM_ID), gens);
+        VmMemoryStat stat = new VmMemoryStat(chunk.get(Key.TIMESTAMP), chunk.get(Key.VM_ID), gens);
+        stat.setAgentId(chunk.get(Key.AGENT_ID));
+        return stat;
     }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -52,6 +52,7 @@
 
     VmMemoryStatDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(vmMemoryStatsCategory);
         getter = new VmLatestPojoListGetter<>(storage, vmMemoryStatsCategory, VmMemoryStat.class);
     }
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/AgentInformation.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/AgentInformation.java	Wed Oct 17 19:08:13 2012 +0200
@@ -44,9 +44,8 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class AgentInformation implements Pojo {
+public class AgentInformation extends BasePojo {
 
-    private String agentId;
     private long startTime;
     private long stopTime;
 
@@ -56,16 +55,6 @@
     private List<BackendInformation> backends = new ArrayList<BackendInformation>();
 
     @Persist
-    public String getAgentId() {
-        return agentId;
-    }
-
-    @Persist
-    public void setAgentId(String agentId) {
-        this.agentId = agentId;
-    }
-
-    @Persist
     public long getStartTime() {
         return startTime;
     }
@@ -107,7 +96,7 @@
 
     @Override
     public String toString() {
-        return "agent " + agentId;
+        return "agent " + getAgentId();
     }
 
     @Override
@@ -122,7 +111,7 @@
             return false;
         }
         AgentInformation other = (AgentInformation) obj;
-        return Objects.equals(this.agentId, other.agentId) &&
+        return super.equals(other) &&
                 Objects.equals(this.alive, other.alive) &&
                 Objects.equals(this.address, other.address) &&
                 Objects.equals(this.startTime, other.startTime) &&
@@ -131,6 +120,6 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(agentId, alive, address, startTime, stopTime);
+        return Objects.hash(getAgentId(), alive, address, startTime, stopTime);
     }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/BackendInformation.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/BackendInformation.java	Wed Oct 17 19:08:13 2012 +0200
@@ -45,7 +45,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class BackendInformation implements Pojo {
+public class BackendInformation extends BasePojo {
 
     private String name;
     private String description;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/BasePojo.java	Wed Oct 17 19:08:13 2012 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 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.common.model;
+
+import java.util.Objects;
+
+import com.redhat.thermostat.common.storage.Persist;
+
+public class BasePojo implements Pojo {
+
+    private String agentId;
+
+    @Persist
+    public final String getAgentId() {
+        return agentId;
+    }
+
+    @Persist
+    public final void setAgentId(String agentId) {
+        this.agentId = agentId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(agentId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        BasePojo other = (BasePojo) obj;
+        return Objects.equals(agentId, other.agentId);
+    }
+
+    
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/CpuStat.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/CpuStat.java	Wed Oct 17 19:08:13 2012 +0200
@@ -42,7 +42,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class CpuStat implements TimeStampedPojo {
+public class CpuStat extends BasePojo implements TimeStampedPojo {
 
     public static final double INVALID_LOAD = Double.MIN_VALUE;
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/HeapInfo.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/HeapInfo.java	Wed Oct 17 19:08:13 2012 +0200
@@ -42,9 +42,8 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class HeapInfo implements TimeStampedPojo {
+public class HeapInfo extends BasePojo implements TimeStampedPojo {
 
-    private String agentId;
     private int vmId;
     private long timeStamp;
 
@@ -62,16 +61,6 @@
     }
 
     @Persist
-    public String getAgentId() {
-        return agentId;
-    }
-
-    @Persist
-    public void setAgentId(String agentId) {
-        this.agentId = agentId;
-    }
-
-    @Persist
     public void setVmId(int vmId) {
         this.vmId = vmId;
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/HostInfo.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/HostInfo.java	Wed Oct 17 19:08:13 2012 +0200
@@ -40,9 +40,8 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class HostInfo implements Pojo {
+public class HostInfo extends BasePojo {
 
-    private String agentId;
     private String hostname;
     private String osName;
     private String osKernel;
@@ -64,16 +63,6 @@
     }
 
     @Persist
-    public String getAgentId() {
-        return agentId;
-    }
-
-    @Persist
-    public void setAgentId(String agentId) {
-        this.agentId = agentId;
-    }
-
-    @Persist
     public void setHostname(String hostname) {
         this.hostname = hostname;
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/MemoryStat.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/MemoryStat.java	Wed Oct 17 19:08:13 2012 +0200
@@ -40,7 +40,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class MemoryStat implements TimeStampedPojo {
+public class MemoryStat extends BasePojo implements TimeStampedPojo {
 
     private long timeStamp;
     private long total;
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/NetworkInterfaceInfo.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/NetworkInterfaceInfo.java	Wed Oct 17 19:08:13 2012 +0200
@@ -40,7 +40,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class NetworkInterfaceInfo implements Pojo {
+public class NetworkInterfaceInfo extends BasePojo {
 
     private String iFace;
     private String ip4Addr;
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/Pojo.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/Pojo.java	Wed Oct 17 19:08:13 2012 +0200
@@ -42,4 +42,6 @@
  */
 public interface Pojo {
 
+    void setAgentId(String agentId);
+    String getAgentId();
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmClassStat.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmClassStat.java	Wed Oct 17 19:08:13 2012 +0200
@@ -40,7 +40,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class VmClassStat implements TimeStampedPojo {
+public class VmClassStat extends BasePojo implements TimeStampedPojo {
 
     private int vmId;
     private long timestamp;
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java	Wed Oct 17 19:08:13 2012 +0200
@@ -40,7 +40,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class VmCpuStat implements TimeStampedPojo {
+public class VmCpuStat extends BasePojo implements TimeStampedPojo {
 
     private long timeStamp;
     private int vmId;
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmGcStat.java	Wed Oct 17 19:08:13 2012 +0200
@@ -39,7 +39,7 @@
 import com.redhat.thermostat.common.storage.Entity;
 
 @Entity
-public class VmGcStat implements TimeStampedPojo {
+public class VmGcStat extends BasePojo implements TimeStampedPojo {
 
     private long timeStamp;
     private int vmId;
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmInfo.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmInfo.java	Wed Oct 17 19:08:13 2012 +0200
@@ -44,7 +44,7 @@
 import com.redhat.thermostat.common.storage.Persist;
 
 @Entity
-public class VmInfo implements Pojo {
+public class VmInfo extends BasePojo {
 
     private int vmPid = 0;
     private long startTime = System.currentTimeMillis();
--- a/common/core/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/VmMemoryStat.java	Wed Oct 17 19:08:13 2012 +0200
@@ -38,7 +38,7 @@
 
 import java.util.List;
 
-public class VmMemoryStat implements TimeStampedPojo {
+public class VmMemoryStat extends BasePojo implements TimeStampedPojo {
 
     public static class Generation {
         public static final String COLLECTOR_NONE = "none";
@@ -66,9 +66,13 @@
         public long used;
     }
 
-    private final List<Generation> generations;
-    private final long timestamp;
-    private final int vmId;
+    private List<Generation> generations;
+    private long timestamp;
+    private int vmId;
+
+    public VmMemoryStat() {
+        this(-1, -1, null);
+    }
 
     public VmMemoryStat(long timestamp, int vmId, List<Generation> generations) {
         this.timestamp = timestamp;
@@ -80,15 +84,27 @@
         return vmId;
     }
 
+    public void setVmId(int vmId) {
+        this.vmId = vmId;
+    }
+
     @Override
     public long getTimeStamp() {
         return timestamp;
     }
 
+    public void setTimeStamp(long timeStamp) {
+        this.timestamp = timeStamp;
+    }
+
     public List<Generation> getGenerations() {
         return generations;
     }
 
+    public void setGenerations(List<Generation> generations) {
+        this.generations = generations;
+    }
+
     public Generation getGeneration(String name) {
         for (Generation g : generations) {
             if (g.name.equals(name)) {
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/AbstractQuery.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/AbstractQuery.java	Wed Oct 17 19:08:13 2012 +0200
@@ -85,7 +85,6 @@
         }
     }
 
-    private Category category;
     private List<Sort> sorts;
     private int limit = -1;
 
@@ -94,20 +93,6 @@
     }
 
     @Override
-    public Query from(Category category) {
-        this.category = category;
-        return this;
-    }
-
-    public Category getCategory() {
-        return category;
-    }
-
-    public void setCategory(Category category) {
-        this.category = category;
-    }
-
-    @Override
     public <T> Query sort(Key<T> key, SortDirection direction) {
         sorts.add(new Sort(key, direction));
         return this;
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Category.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Category.java	Wed Oct 17 19:08:13 2012 +0200
@@ -43,10 +43,12 @@
 import java.util.Objects;
 
 public class Category {
-    private final String name;
+    private String name;
     private final Map<String, Key<?>> keys;
 
-    private ConnectionKey connectionKey;
+    public Category() {
+        this(null);
+    }
 
     /**
      * Creates a new Category instance with the specified name.
@@ -56,36 +58,32 @@
      * @throws IllegalArgumentException if a Category is created with a name that has been used before
      */
     public Category(String name, Key<?>... keys) {
-        if (Categories.contains(name)) {
-            throw new IllegalStateException();
-        }
-        this.name = name;
         Map<String, Key<?>> keysMap = new HashMap<String, Key<?>>();
         for (Key<?> key : keys) {
             keysMap.put(key.getName(), key);
         }
         this.keys = Collections.unmodifiableMap(keysMap);
-        Categories.add(this);
+        setName(name);
     }
 
     public String getName() {
         return name;
     }
 
-    public synchronized Collection<Key<?>> getKeys() {
-        return keys.values();
+    public void setName(String name) {
+        if (Categories.contains(name)) {
+            throw new IllegalStateException();
+        }
+
+        this.name = name;
+
+        if (name != null) {
+            Categories.add(this);
+        }
     }
 
-    public void setConnectionKey(ConnectionKey connKey) {
-        connectionKey = connKey;
-    }
-
-    public ConnectionKey getConnectionKey() {
-        return connectionKey;
-    }
-
-    public boolean hasBeenRegistered() {
-        return getConnectionKey() != null;
+    public synchronized Collection<Key<?>> getKeys() {
+        return keys.values();
     }
 
     public Key<?> getKey(String name) {
@@ -94,7 +92,10 @@
 
     @Override
     public String toString() {
-        return getName();
+        return getName() + keys;
+    }
+    public int hashCode() {
+        return Objects.hash(name, keys);
     }
 
     public boolean equals(Object o) {
@@ -102,6 +103,6 @@
             return false;
         }
         Category other = (Category) o;
-        return Objects.equals(name, other.name) && keys.equals(other.keys);
+        return Objects.equals(name, other.name) && Objects.equals(keys, other.keys);
     }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Key.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Key.java	Wed Oct 17 19:08:13 2012 +0200
@@ -51,6 +51,12 @@
     private String name;
     private boolean isPartialCategoryKey;
 
+    public Key() {
+        // This is used only in de-serialization, e.g. using Gson, and therefore
+        // we do not check the name for null or empty.
+        super();
+    }
+
     public Key(String name, boolean isPartialCategoryKey) {
         if (name == null || name.length() == 0) {
             throw new IllegalArgumentException("A Key must have a non-null name of length >= 1.");
@@ -63,10 +69,19 @@
         return name;
     }
 
+    public void setName(String name) {
+        this.name = name;
+    }
+
     public boolean isPartialCategoryKey() {
         return isPartialCategoryKey;
     }
 
+    public void setPartialCategoryKey(boolean partialCategoryKey) {
+        this.isPartialCategoryKey = partialCategoryKey;
+
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoQuery.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoQuery.java	Wed Oct 17 19:08:13 2012 +0200
@@ -45,6 +45,7 @@
 
     private BasicDBObject query = new BasicDBObject();
     private boolean hasClauses = false;
+    private Category category;
 
     @Override
     public MongoQuery from(Category category) {
@@ -52,6 +53,14 @@
         return this;
     }
 
+    public Category getCategory() {
+        return category;
+    }
+
+    public void setCategory(Category category) {
+        this.category = category;
+    }
+
     @Override
     public <T> MongoQuery where(Key<T> key, Criteria operator, T value) {
         return where(key.getName(), operator, value);
@@ -88,10 +97,6 @@
         return this;
     }
 
-    String getCollectionName() {
-        return getCategory().getName();
-    }
-
     DBObject getGeneratedQuery() {
         return query;
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Wed Oct 17 19:08:13 2012 +0200
@@ -73,7 +73,7 @@
     private DB db = null;
     private Map<String, DBCollection> collectionCache = new HashMap<String, DBCollection>();
 
-    private UUID agentId = null;
+    private UUID agentId;
 
     private Map<Class<?>, Converter<?>> converters;
 
@@ -130,14 +130,14 @@
         } else if (chunk.get(Key.AGENT_ID) != null) {
             return new BasicDBObject(Key.AGENT_ID.getName(), chunk.get(Key.AGENT_ID));
         } else {
-            return null;
+            return new BasicDBObject();
         }
     }
 
     // TODO: Make this private, and change the testcase to test putPojo() instead.
     void putChunk(Chunk chunk) {
         Category cat = chunk.getCategory();
-        DBCollection coll = getCachedCollection(cat.getName());
+        DBCollection coll = getCachedCollection(cat);
         BasicDBObject toInsert = getAgentQueryKeyFromChunkOrGlobalAgent(chunk);
         BasicDBObject replaceKey = null;
         boolean replace = chunk.getReplace();
@@ -206,7 +206,7 @@
 
     void updateChunk(Chunk chunk) {
         Category cat = chunk.getCategory();
-        DBCollection coll = getCachedCollection(cat.getName());
+        DBCollection coll = getCachedCollection(cat);
         BasicDBObject toUpdate = new BasicDBObject();
         BasicDBObject updateKey = getAgentQueryKeyFromChunkOrGlobalAgent(chunk);
         BasicDBObject setObj = null;
@@ -279,7 +279,7 @@
         MongoRemove mongoRemove = (MongoRemove) remove;
         Chunk query = mongoRemove.getChunk();
         Category category = query.getCategory();
-        DBCollection coll = getCachedCollection(category.getName());
+        DBCollection coll = getCachedCollection(category);
 
         BasicDBObject toRemove = getAgentQueryKeyFromChunkOrGlobalAgent(query);
         for (Key<?> key : category.getKeys()) {
@@ -291,13 +291,11 @@
         coll.remove(toRemove);
     }
 
-    private DBCollection getCachedCollection(String collName) {
+    private DBCollection getCachedCollection(Category category) {
+        String collName = category.getName();
         DBCollection coll = collectionCache.get(collName);
         if (coll == null && db.collectionExists(collName)) {
-            coll = db.getCollection(collName);
-            if (coll != null) {
-                collectionCache.put(collName, coll);
-            }
+            throw new IllegalStateException("Categories need to be registered before being used");
         }
         return coll;
     }
@@ -319,15 +317,24 @@
     }
     
     @Override
-    public ConnectionKey createConnectionKey(Category category) {
+    public void registerCategory(Category category) {
+        String name = category.getName();
+        if (collectionCache.containsKey(name)) {
+            throw new IllegalStateException("Category may only be associated with one backend.");
+        }
+
+        DBCollection coll;
+        if (! db.collectionExists(name)) {
+            coll = db.createCollection(name, new BasicDBObject("capped", false));
+        } else {
+            coll = db.getCollection(name);
+        }
+        collectionCache.put(name, coll);
+    }
+
+    private void createConnectionKey(Category category) {
         // TODO: There is probably some better place to do this, perhaps related to the inner class
         // idea mentioned below.
-        if (!db.collectionExists(category.getName())) {
-            db.createCollection(category.getName(), new BasicDBObject("capped", false));
-        }
-        // TODO: We want to return an instance of an inner class here that carries the actual connection
-        // and replace the collectionCache. For now this is good enough though.
-        return new ConnectionKey(){};
     }
 
     @Override
@@ -348,7 +355,7 @@
     @Override
     public <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) {
         MongoQuery mongoQuery =  checkAndCastQuery(query);
-        DBCollection coll = getCachedCollection(mongoQuery.getCollectionName());
+        DBCollection coll = getCachedCollection(mongoQuery.getCategory());
         DBCursor dbCursor;
         if (mongoQuery.hasClauses()) {
             dbCursor = coll.find(mongoQuery.getGeneratedQuery());
@@ -385,7 +392,7 @@
     // TODO: Make this private, and change the testcase to test putPojo() instead.
     Chunk find(Query query) {
         MongoQuery mongoQuery = checkAndCastQuery(query);
-        DBCollection coll = getCachedCollection(mongoQuery.getCollectionName());
+        DBCollection coll = getCachedCollection(mongoQuery.getCategory());
         DBObject dbResult = coll.findOne(mongoQuery.getGeneratedQuery());
         ChunkConverter converter = new ChunkConverter();
         return dbResult == null ? null : converter.dbObjectToChunk(dbResult, mongoQuery.getCategory());
@@ -399,10 +406,10 @@
         return (MongoQuery) query;
 
     }
-    
+
     @Override
     public long getCount(Category category) {
-        DBCollection coll = getCachedCollection(category.getName());
+        DBCollection coll = getCachedCollection(category);
         if (coll != null) {
             return coll.getCount();
         }
@@ -433,8 +440,7 @@
         putChunk(chunk);
     }
 
-    private Chunk convertPojoToChunk(Category category, boolean replace,
-            Pojo pojo) {
+    private Chunk convertPojoToChunk(Category category, boolean replace, Pojo pojo) {
         Converter customConverter = converters.get(pojo.getClass());
         Chunk chunk;
         if (customConverter != null) {
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorageProvider.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorageProvider.java	Wed Oct 17 19:08:13 2012 +0200
@@ -36,6 +36,9 @@
 
 package com.redhat.thermostat.common.storage;
 
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
 import com.redhat.thermostat.common.config.StartupConfiguration;
 
 public class MongoStorageProvider implements StorageProvider {
@@ -48,7 +51,9 @@
 
     @Override
     public Storage createStorage() {
-        return new MongoStorage(configuration);
+        BundleContext ctx = FrameworkUtil.getBundle(getClass()).getBundleContext();
+        Storage restStorage = (Storage) ctx.getService(ctx.getServiceReference("com.redhat.thermostat.web.client.RESTStorage"));
+        return restStorage;
     }
 
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Wed Oct 17 19:08:13 2012 +0200
@@ -47,18 +47,10 @@
 
     public abstract String getAgentId();
 
-    public final void registerCategory(Category category) {
-        if (category.hasBeenRegistered()) {
-            throw new IllegalStateException("Category may only be associated with one backend.");
-        }
-        ConnectionKey connKey = createConnectionKey(category);
-        category.setConnectionKey(connKey);
-    }
+    public abstract void registerCategory(Category category);
 
     public abstract Connection getConnection();
 
-    public abstract ConnectionKey createConnectionKey(Category category);
-
     public abstract void putPojo(Category category, boolean replace, Pojo pojo);
 
     public abstract void updatePojo(Update update);
--- a/common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java	Wed Oct 17 19:08:13 2012 +0200
@@ -43,6 +43,7 @@
 import com.redhat.thermostat.common.storage.AbstractQuery;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.MongoQuery;
 
 public class MockQuery extends AbstractQuery {
 
@@ -79,6 +80,7 @@
     }
 
     private final List<WhereClause<?>> whereClauses = new ArrayList<>();
+    private Category category;
 
     @Override
     public MockQuery from(Category category) {
@@ -86,6 +88,14 @@
         return this;
     }
 
+    public Category getCategory() {
+        return category;
+    }
+
+    public void setCategory(Category category) {
+        this.category = category;
+    }
+
     @Override
     public <T> MockQuery where(Key<T> key, Criteria criteria, T value) {
         whereClauses.add(new WhereClause<>(key, criteria, value));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -232,7 +232,7 @@
         
         // verify a connection key has been created before requesting the
         // heap dumps
-        verify(storage).createConnectionKey(HeapDAO.heapInfoCategory);
+        verify(storage).registerCategory(HeapDAO.heapInfoCategory);
         
         HostRef host = new HostRef("123", "test-host");
         VmRef vm = new VmRef(host, 234, "test-vm");
--- a/common/core/src/test/java/com/redhat/thermostat/common/model/TimeStampedPojoCorrelatorTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/model/TimeStampedPojoCorrelatorTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -48,7 +48,7 @@
 
 public class TimeStampedPojoCorrelatorTest {
 
-    private static class TestTimeStampedPojo implements TimeStampedPojo {
+    private static class TestTimeStampedPojo extends BasePojo implements TimeStampedPojo {
 
         private long timestamp;
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/CategoryTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/CategoryTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -37,7 +37,6 @@
 package com.redhat.thermostat.common.storage;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -48,15 +47,6 @@
 public class CategoryTest {
 
     @Test
-    public void testHasBeenRegistered() {
-        Category category1 = new Category("testHasBeenRegistered");
-        assertFalse(category1.hasBeenRegistered());
-        ConnectionKey connKey = new ConnectionKey(){};
-        category1.setConnectionKey(connKey);
-        assertTrue(category1.hasBeenRegistered());
-    }
-
-    @Test
     public void testGetKey() {
         Key<String> key1 = new Key<String>("key1", false);
         Category category = new Category("testGetKey", key1);
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoCursorTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoCursorTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -43,23 +43,21 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
-import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.model.BasePojo;
 
 public class MongoCursorTest {
 
     @Entity
-    public static class TestClass implements Pojo {
+    public static class TestClass extends BasePojo {
         private String key1;
         private String key2;
         private String key3;
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoQueryTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoQueryTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -57,7 +57,7 @@
     @Test
     public void testCollectionName() {
         MongoQuery query = new MongoQuery().from(new Category("some-collection"));
-        assertEquals("some-collection", query.getCollectionName());
+        assertEquals("some-collection", query.getCategory().getName());
     }
 
     @Test
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -75,7 +75,7 @@
 import com.mongodb.gridfs.GridFSDBFile;
 import com.mongodb.gridfs.GridFSInputFile;
 import com.redhat.thermostat.common.config.StartupConfiguration;
-import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.model.BasePojo;
 import com.redhat.thermostat.common.storage.Query.Criteria;
 
 @RunWith(PowerMockRunner.class)
@@ -83,7 +83,7 @@
 public class MongoStorageTest {
 
     @Entity
-    public static class TestClass implements Pojo {
+    public static class TestClass extends BasePojo {
         private String key1;
         private String key2;
         private String key3;
@@ -204,16 +204,6 @@
         cursor = null;
     }
 
-    @Test
-    public void testCreateConnectionKey() throws Exception {
-        PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
-        MongoStorage storage = makeStorage();
-        storage.getConnection().connect();
-        Category category = new Category("testCreateConnectionKey");
-        ConnectionKey connKey = storage.createConnectionKey(category);
-        assertNotNull(connKey);
-    }
-
     @Test (expected=IllegalArgumentException.class)
     public void verifyFindOnlyAcceptsMongoQuery() {
         MongoStorage storage = makeStorage();
@@ -273,7 +263,6 @@
         when(query.hasClauses()).thenReturn(true);
         DBObject generatedQuery = mock(DBObject.class);
         when(query.getGeneratedQuery()).thenReturn(generatedQuery);
-        when(query.getCollectionName()).thenReturn(testCategory.getName());
         when(query.getCategory()).thenReturn(testCategory);
         ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class);
 
@@ -291,7 +280,6 @@
         MongoQuery query = mock(MongoQuery.class);
         DBObject generatedQuery = mock(DBObject.class);
         when(query.getGeneratedQuery()).thenReturn(generatedQuery);
-        when(query.getCollectionName()).thenReturn(testCategory.getName());
         when(query.getCategory()).thenReturn(testCategory);
 
         ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class);
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/StorageTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 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.common.storage;
-
-import static org.junit.Assert.assertSame;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class StorageTest {
-
-    private Storage storage;
-    private ConnectionKey connKey;
-
-    @Before
-    public void setUp() {
-        storage = mock(Storage.class);
-        connKey = new ConnectionKey(){};
-        when(storage.createConnectionKey(any(Category.class))).thenReturn(connKey);
-    }
-
-    @After
-    public void tearDown() {
-        storage = null;
-        connKey = null;
-    }
-
-    @Test
-    public void testRegisterCategory() {
-        Category category = new Category("testRegisterCategory");
-        storage.registerCategory(category);
-
-        verify(storage).createConnectionKey(category);
-        assertSame(connKey, category.getConnectionKey());
-    }
-
-    @Test(expected=IllegalStateException.class)
-    public void testRegisterCategoryTwice() {
-
-        Category category = new Category("test");
-        storage.registerCategory(category);
-        storage.registerCategory(category);
-    }
-
-    @Test(expected=IllegalStateException.class)
-    public void testRegisterCategorySameName() {
-
-        Category category1 = new Category("test");
-        storage.registerCategory(category1);
-        Category category2 = new Category("test");
-        storage.registerCategory(category2);
-    }
-}
--- a/distribution/config/commands/gui.properties	Tue Oct 16 14:23:29 2012 -0400
+++ b/distribution/config/commands/gui.properties	Wed Oct 17 19:08:13 2012 +0200
@@ -1,4 +1,7 @@
 bundles = thermostat-common-core-@project.version@.jar, \
+          gson-2.2.2.jar, \
+          thermostat-web-common-@project.version@.jar, \
+          thermostat-web-client-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-core-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
--- a/distribution/config/commands/service.properties	Tue Oct 16 14:23:29 2012 -0400
+++ b/distribution/config/commands/service.properties	Wed Oct 17 19:08:13 2012 +0200
@@ -1,9 +1,23 @@
 bundles = thermostat-agent-core-@project.version@.jar, \
+          gson-2.2.2.jar, \
+          thermostat-web-common-@project.version@.jar, \
+          thermostat-web-server-@project.version@.jar, \
+          thermostat-web-client-@project.version@.jar, \
           thermostat-osgi-process-handler-@project.version@.jar, \
           thermostat-common-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-agent-command-@project.version@.jar, \
-          thermostat-agent-cli-@project.version@.jar
+          thermostat-agent-cli-@project.version@.jar, \
+          thermostat-thread-collector-@project.version@.jar, \
+          jetty-continuation-8.1.5.v20120716.jar, \
+          jetty-http-8.1.5.v20120716.jar, \
+          jetty-io-8.1.5.v20120716.jar, \
+          jetty-security-8.1.5.v20120716.jar, \
+          jetty-server-8.1.5.v20120716.jar, \
+          jetty-servlet-8.1.5.v20120716.jar, \
+          jetty-util-8.1.5.v20120716.jar, \
+          jetty-webapp-8.1.5.v20120716.jar, \
+          jetty-xml-8.1.5.v20120716.jar
 
 description = starts and stops the thermostat storage and agent
 
--- a/distribution/config/osgi-export.properties	Tue Oct 16 14:23:29 2012 -0400
+++ b/distribution/config/osgi-export.properties	Wed Oct 17 19:08:13 2012 +0200
@@ -83,3 +83,18 @@
 org.apache.lucene.search
 org.apache.lucene.store
 org.apache.lucene.util
+
+org.eclipse.jetty.server=8.1.0
+org.eclipse.jetty.server.handler=8.1.0
+org.eclipse.jetty.webapp=8.1.0
+org.eclipse.jetty.servlet=8.1.0
+org.eclipse.jetty.servlet.descriptor=8.1.0
+org.eclipse.jetty.continuation=8.1.0
+org.eclipse.jetty.http=8.1.0
+org.eclipse.jetty.io=8.1.0
+org.eclipse.jetty.security=8.1.0
+org.eclipse.jetty.util=8.1.0
+org.eclipse.jetty.xml=8.1.0
+javax.servlet=2.6.0
+javax.servlet.descriptor=2.6.0
+javax.servlet.http=2.6.0
--- a/distribution/pom.xml	Tue Oct 16 14:23:29 2012 -0400
+++ b/distribution/pom.xml	Wed Oct 17 19:08:13 2012 +0200
@@ -337,6 +337,26 @@
         <artifactId>thermostat-keyring</artifactId>
         <version>${project.version}</version>
     </dependency>
+    <dependency>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-web-client</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-web-server</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>8.1.5.v20120716</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>8.1.5.v20120716</version>
+    </dependency>
 
     <!--  thread plugin -->
     <dependency>
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Wed Oct 17 19:08:13 2012 +0200
@@ -56,9 +56,9 @@
     private Storage storage; 
     public ThreadDaoImpl(Storage storage) {
         this.storage = storage;
-        storage.createConnectionKey(THREAD_CAPABILITIES);
-        storage.createConnectionKey(THREAD_SUMMARY);
-        storage.createConnectionKey(THREAD_INFO);
+        storage.registerCategory(THREAD_CAPABILITIES);
+        storage.registerCategory(THREAD_SUMMARY);
+        storage.registerCategory(THREAD_INFO);
     }
 
     @Override
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java	Wed Oct 17 19:08:13 2012 +0200
@@ -39,13 +39,14 @@
 import java.lang.Thread.State;
 import java.util.Arrays;
 
+import com.redhat.thermostat.common.model.BasePojo;
 import com.redhat.thermostat.common.model.TimeStampedPojo;
 import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Persist;
 
 
 @Entity
-public class ThreadInfoData implements TimeStampedPojo {
+public class ThreadInfoData extends BasePojo implements TimeStampedPojo {
 
     private int vmId;
     private StackTraceElement[] stackTrace;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java	Wed Oct 17 19:08:13 2012 +0200
@@ -36,13 +36,14 @@
 
 package com.redhat.thermostat.thread.model;
 
+import com.redhat.thermostat.common.model.BasePojo;
 import com.redhat.thermostat.common.model.TimeStampedPojo;
 import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Persist;
 
 
 @Entity
-public class ThreadSummary implements TimeStampedPojo {
+public class ThreadSummary extends BasePojo implements TimeStampedPojo {
 
     private int vmId;
     private long currentLiveThreads;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java	Wed Oct 17 19:08:13 2012 +0200
@@ -41,13 +41,13 @@
 import java.util.List;
 import java.util.Set;
 
-import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.model.BasePojo;
 import com.redhat.thermostat.common.storage.Entity;
 import com.redhat.thermostat.common.storage.Persist;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 
 @Entity
-public class VMThreadCapabilities implements Pojo {
+public class VMThreadCapabilities extends BasePojo {
     
     private Set<String> features = new HashSet<>();
 
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -65,9 +65,9 @@
         @SuppressWarnings("unused")
         ThreadDaoImpl dao = new ThreadDaoImpl(storage);
         
-        verify(storage).createConnectionKey(ThreadDao.THREAD_CAPABILITIES);
-        verify(storage).createConnectionKey(ThreadDao.THREAD_INFO);
-        verify(storage).createConnectionKey(ThreadDao.THREAD_SUMMARY);
+        verify(storage).registerCategory(ThreadDao.THREAD_CAPABILITIES);
+        verify(storage).registerCategory(ThreadDao.THREAD_INFO);
+        verify(storage).registerCategory(ThreadDao.THREAD_SUMMARY);
     }
     
     @Test
--- a/web/client/pom.xml	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/client/pom.xml	Wed Oct 17 19:08:13 2012 +0200
@@ -46,7 +46,7 @@
   </parent>
 
   <artifactId>thermostat-web-client</artifactId>
-  <packaging>jar</packaging>
+  <packaging>bundle</packaging>
 
   <name>Thermostat Web Client</name>
 
@@ -64,6 +64,17 @@
     </dependency>
 
     <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
       <version>8.1.5.v20120716</version>
@@ -90,4 +101,25 @@
 
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>com.redhat.thermostat.web.client</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-Activator>com.redhat.thermostat.web.client.Activator</Bundle-Activator>
+            <Export-Package>
+              com.redhat.thermostat.web.client
+            </Export-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/Activator.java	Wed Oct 17 19:08:13 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 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.web.client;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.common.storage.Storage;
+
+public class Activator implements BundleActivator {
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        RESTStorage storage = new RESTStorage();
+        context.registerService(RESTStorage.class.getName(), storage, null);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+}
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java	Wed Oct 17 19:08:13 2012 +0200
@@ -42,16 +42,19 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.Reader;
 import java.lang.reflect.Array;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.UUID;
 
 import com.google.gson.Gson;
 import com.redhat.thermostat.common.model.Pojo;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Connection;
-import com.redhat.thermostat.common.storage.ConnectionKey;
 import com.redhat.thermostat.common.storage.Cursor;
 import com.redhat.thermostat.common.storage.Query;
 import com.redhat.thermostat.common.storage.Remove;
@@ -62,16 +65,70 @@
 
 public class RESTStorage extends Storage {
 
+    private final class WebConnection extends Connection {
+        WebConnection() {
+            connected = true;
+        }
+        @Override
+        public void disconnect() {
+            connected = false;
+            fireChanged(ConnectionStatus.DISCONNECTED);
+        }
+
+        @Override
+        public void connect() {
+            connected = true;
+            fireChanged(ConnectionStatus.CONNECTED);
+        }
+        @Override
+        public String getUrl() {
+            // TODO Auto-generated method stub
+            return endpoint;
+        }
+    }
+
     private String endpoint;
+    private UUID agentId;
+
+    private Map<Category, Integer> categoryIds;
+
+    public RESTStorage() {
+        endpoint = "http://localhost:8082";
+        categoryIds = new HashMap<>();
+    }
 
     @Override
-    public ConnectionKey createConnectionKey(Category arg0) {
-        return new ConnectionKey() {};
+    public void registerCategory(Category category) {
+        try {
+            URL url = new URL(endpoint + "/register-category");
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            String enc = "UTF-8";
+            conn.setRequestProperty("Content-Encoding", enc);
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            conn.setRequestMethod("POST");
+            OutputStream out = conn.getOutputStream();
+            Gson gson = new Gson();
+            OutputStreamWriter writer = new OutputStreamWriter(out);
+            writer.write("name=");
+            writer.write(URLEncoder.encode(category.getName(), enc));
+            writer.write("&category=");
+            writer.write(URLEncoder.encode(gson.toJson(category), enc));
+            writer.flush();
+
+            InputStream in = conn.getInputStream();
+            Reader reader = new InputStreamReader(in);
+            Integer id = gson.fromJson(reader, Integer.class);
+            categoryIds.put(category, id);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+
     }
 
     @Override
     public Query createQuery() {
-        return new RESTQuery();
+        return new RESTQuery(categoryIds);
     }
 
     @Override
@@ -134,14 +191,12 @@
 
     @Override
     public String getAgentId() {
-        // TODO Auto-generated method stub
-        return null;
+        return agentId.toString();
     }
 
     @Override
     public Connection getConnection() {
-        // TODO Auto-generated method stub
-        return null;
+        return new WebConnection();
     }
 
     @Override
@@ -164,8 +219,13 @@
 
     @Override
     public void putPojo(Category category, boolean replace, Pojo pojo) {
+        // TODO: This logic should probably be moved elsewhere. I.e. out of the Storage API.
+        if (pojo.getAgentId() == null) {
+            pojo.setAgentId(getAgentId());
+        }
         try {
-            WebInsert insert = new WebInsert(category, replace, pojo.getClass().getName());
+            int categoryId = categoryIds.get(category);
+            WebInsert insert = new WebInsert(categoryId, replace, pojo.getClass().getName());
             URL url = new URL(endpoint + "/put-pojo");
             HttpURLConnection conn = (HttpURLConnection) url.openConnection();
             conn.setDoOutput(true);
@@ -175,9 +235,9 @@
             Gson gson = new Gson();
             OutputStreamWriter writer = new OutputStreamWriter(out);
             writer.write("insert=");
-            gson.toJson(insert, writer);
+            writer.write(URLEncoder.encode(gson.toJson(insert), "UTF-8"));
             writer.write("&pojo=");
-            gson.toJson(pojo, writer);
+            writer.write(URLEncoder.encode(gson.toJson(pojo), "UTF-8"));
             writer.flush();
 
             InputStream in = conn.getInputStream();
@@ -199,9 +259,8 @@
     }
 
     @Override
-    public void setAgentId(UUID arg0) {
-        // TODO Auto-generated method stub
-
+    public void setAgentId(UUID agentId) {
+        this.agentId = agentId;
     }
 
     @Override
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/RESTStorageTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/RESTStorageTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -45,9 +45,10 @@
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
+import java.net.URLDecoder;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
+import java.util.UUID;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -89,6 +90,8 @@
     private static Category category;
     private static Key<String> key1;
 
+    private RESTStorage storage;
+
     @BeforeClass
     public static void setupCategory() {
         key1 = new Key<>("property1", true);
@@ -110,6 +113,11 @@
                 startServer(port);
             }
         });
+
+        storage = new RESTStorage();
+        storage.setEndpoint("http://localhost:" + port + "/");
+        storage.setAgentId(new UUID(123, 456));
+        registerCategory();
     }
 
     private void startServer(int port) throws Exception {
@@ -144,14 +152,24 @@
 
     @After
     public void tearDown() throws Exception {
+
+        storage = null;
+
         server.stop();
         server.join();
     }
 
+    private void registerCategory() {
+
+        // Return 42 for categoryId.
+        Gson gson = new Gson();
+        responseBody = gson.toJson(42);
+
+        storage.registerCategory(category);
+    }
+
     @Test
     public void testFindPojo() {
-        RESTStorage storage = new RESTStorage();
-        storage.setEndpoint("http://localhost:" + port + "/");
 
         TestObj obj = new TestObj();
         obj.setProperty1("fluffor");
@@ -163,11 +181,7 @@
         TestObj result = storage.findPojo(query, TestObj.class);
         RESTQuery restQuery = gson.fromJson(requestBody, RESTQuery.class);
 
-        Category actualCategory = restQuery.getCategory();
-        assertEquals("test", actualCategory.getName());
-        Collection<Key<?>> keys = actualCategory.getKeys();
-        assertEquals(1, keys.size());
-        assertTrue(keys.contains(new Key<String>("property1", true)));
+        assertEquals(42, restQuery.getCategoryId());
         List<Qualifier<?>> qualifiers = restQuery.getQualifiers();
         assertEquals(1, qualifiers.size());
         Qualifier<?> qual = qualifiers.get(0);
@@ -180,8 +194,6 @@
 
     @Test
     public void testFindAllPojos() {
-        RESTStorage storage = new RESTStorage();
-        storage.setEndpoint("http://localhost:" + port + "/");
 
         TestObj obj1 = new TestObj();
         obj1.setProperty1("fluffor1");
@@ -196,11 +208,7 @@
         Cursor<TestObj> results = storage.findAllPojos(query, TestObj.class);
         RESTQuery restQuery = gson.fromJson(requestBody, RESTQuery.class);
 
-        Category actualCategory = restQuery.getCategory();
-        assertEquals("test", actualCategory.getName());
-        Collection<Key<?>> keys = actualCategory.getKeys();
-        assertEquals(1, keys.size());
-        assertTrue(keys.contains(new Key<String>("property1", true)));
+        assertEquals(42, restQuery.getCategoryId());
         List<Qualifier<?>> qualifiers = restQuery.getQualifiers();
         assertEquals(1, qualifiers.size());
         Qualifier<?> qual = qualifiers.get(0);
@@ -217,8 +225,7 @@
 
     @Test
     public void testPut() throws IOException, JsonSyntaxException, ClassNotFoundException {
-        RESTStorage storage = new RESTStorage();
-        storage.setEndpoint("http://localhost:" + port + "/");
+
         TestObj obj = new TestObj();
         obj.setProperty1("fluff");
 
@@ -227,13 +234,14 @@
         Gson gson = new Gson();
         StringReader reader = new StringReader(requestBody);
         BufferedReader bufRead = new BufferedReader(reader);
-        String line = bufRead.readLine();
+        String line = URLDecoder.decode(bufRead.readLine(), "UTF-8");
         String [] params = line.split("&");
+        System.err.println("params: " + line);
         assertEquals(2, params.length);
         String[] parts = params[0].split("=");
         assertEquals("insert", parts[0]);
         WebInsert insert = gson.fromJson(parts[1], WebInsert.class);
-        assertEquals(category, insert.getCategory());
+        assertEquals(42, insert.getCategoryId());
         assertEquals(true, insert.isReplace());
         assertEquals(TestObj.class.getName(), insert.getPojoClass());
 
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/TestObj.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/TestObj.java	Wed Oct 17 19:08:13 2012 +0200
@@ -37,9 +37,9 @@
 
 package com.redhat.thermostat.web.client;
 
-import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.model.BasePojo;
 
-public class TestObj implements Pojo {
+public class TestObj extends BasePojo {
 
     
     private String property1;
--- a/web/common/pom.xml	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/common/pom.xml	Wed Oct 17 19:08:13 2012 +0200
@@ -46,7 +46,7 @@
   </parent>
 
   <artifactId>thermostat-web-common</artifactId>
-  <packaging>jar</packaging>
+  <packaging>bundle</packaging>
 
   <name>Thermostat Web Common</name>
 
@@ -65,4 +65,25 @@
     </dependency>
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>com.redhat.thermostat.web.common</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Export-Package>
+              com.redhat.thermostat.web.common
+            </Export-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
 </project>
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/RESTQuery.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/RESTQuery.java	Wed Oct 17 19:08:13 2012 +0200
@@ -39,8 +39,10 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import com.redhat.thermostat.common.storage.AbstractQuery;
+import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Query;
 
@@ -49,8 +51,31 @@
     private List<Qualifier<?>> qualifiers;
     private String resultClassName;
 
+    private transient Map<Category, Integer> categoryIdMap;
+
+    private int categoryId;
+
     public RESTQuery() {
+        this(null);
+    }
+
+    public RESTQuery(Map<Category, Integer> categoryIdMap) {
         qualifiers = new ArrayList<>();
+        this.categoryIdMap = categoryIdMap;
+    }
+
+    @Override
+    public Query from(Category category) {
+        categoryId = categoryIdMap.get(category);
+        return this;
+    }
+
+    public int getCategoryId() {
+        return categoryId;
+    }
+
+    public void setCategoryId(int categoryId) {
+        this.categoryId = categoryId;
     }
 
     @Override
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java	Wed Oct 17 19:08:13 2012 +0200
@@ -37,12 +37,26 @@
 
 package com.redhat.thermostat.web.common;
 
+import com.redhat.thermostat.common.config.StartupConfiguration;
+import com.redhat.thermostat.common.storage.MongoStorage;
 import com.redhat.thermostat.common.storage.Storage;
 
 public class StorageWrapper {
 
     private static Storage storage;
     public static Storage getStorage() {
+        if (storage != null) {
+            return storage;
+        }
+        StartupConfiguration conf = new StartupConfiguration() {
+            
+            @Override
+            public String getDBConnectionString() {
+                return "mongodb://127.0.0.1:27518";
+            }
+        };
+        storage = new MongoStorage(conf);
+        storage.getConnection().connect();
         return storage;
     }
     public static void setStorage(Storage storage) {
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java	Wed Oct 17 19:08:13 2012 +0200
@@ -37,30 +37,29 @@
 
 package com.redhat.thermostat.web.common;
 
-import com.redhat.thermostat.common.storage.Category;
 
 public class WebInsert {
 
-    private Category category;
+    private int categoryId;
     private boolean replace;
     private String pojoClass;
 
     public WebInsert() {
-        this(null, false, null);
+        this(-1, false, null);
     }
 
-    public WebInsert(Category category, boolean replace, String pojoClass) {
-        this.category = category;
+    public WebInsert(int categoryId, boolean replace, String pojoClass) {
+        this.categoryId = categoryId;
         this.replace = replace;
         this.pojoClass = pojoClass;
     }
 
-    public Category getCategory() {
-        return category;
+    public int getCategoryId() {
+        return categoryId;
     }
 
-    public void setCategory(Category category) {
-        this.category = category;
+    public void setCategoryId(int categoryId) {
+        this.categoryId = categoryId;
     }
 
     public boolean isReplace() {
--- a/web/common/src/test/java/RESTQueryTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/common/src/test/java/RESTQueryTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -1,7 +1,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.junit.Test;
 
@@ -51,9 +53,11 @@
 
     @Test
     public void test() {
-        RESTQuery query = new RESTQuery();
         Key<String> key1 = new Key<>("testkey", true);
         Category category = new Category("test", key1);
+        Map<Category,Integer> categoryIdMap = new HashMap<>();
+        categoryIdMap.put(category, 42);
+        RESTQuery query = new RESTQuery(categoryIdMap);
         query.from(category).where(key1, Criteria.EQUALS, "fluff");
 
         List<Qualifier<?>> qualifiers = query.getQualifiers();
@@ -63,6 +67,6 @@
         assertEquals(Criteria.EQUALS, qualifier.getCriteria());
         assertEquals("fluff", qualifier.getValue());
 
-        assertSame(category, query.getCategory());
+        assertEquals(42, query.getCategoryId());
     }
 }
--- a/web/server/pom.xml	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/server/pom.xml	Wed Oct 17 19:08:13 2012 +0200
@@ -46,7 +46,7 @@
   </parent>
 
   <artifactId>thermostat-web-server</artifactId>
-  <packaging>war</packaging>
+  <packaging>bundle</packaging>
 
   <name>Thermostat Web Server</name>
 
@@ -74,13 +74,11 @@
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
       <version>8.1.5.v20120716</version>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-webapp</artifactId>
       <version>8.1.5.v20120716</version>
-      <scope>test</scope>
     </dependency>
 
 
@@ -95,6 +93,7 @@
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
       <version>2.5</version>
+      <scope>provided</scope>
     </dependency>
 
     <dependency>
@@ -104,11 +103,53 @@
     </dependency>
 
     <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
       <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-web-common</artifactId>
       <version>${project.version}</version>
     </dependency>
 
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-thread-collector</artifactId>
+      <version>${project.version}</version>
+      <scope>compile</scope>
+    </dependency>
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>com.redhat.thermostat.web.server</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-Activator>com.redhat.thermostat.web.server.Activator</Bundle-Activator>
+            <Export-Package>
+              com.redhat.thermostat.web.server
+            </Export-Package>
+            <Import-Package>
+              com.redhat.thermostat.thread.model,
+              *
+            </Import-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/Activator.java	Wed Oct 17 19:08:13 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 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.web.server;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletMapping;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+    private Server server;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        server = new Server(8082);
+        ServletHandler handler = new ServletHandler();
+        ServletHolder servletHolder = new ServletHolder("rest-storage-end-point", new RESTStorageEndPoint());
+        handler.setServlets(new ServletHolder[] { servletHolder });
+        ServletMapping mapping = new ServletMapping();
+        mapping.setPathSpec("/");
+        mapping.setServletName("rest-storage-end-point");
+        handler.setServletMappings(new ServletMapping[] { mapping });
+        server.setHandler(handler); //new WebAppContext("/home/rkennke/src/thermostat/distribution/target/libs/thermostat-web-server-0.5.0-SNAPSHOT.war", "/"));
+
+        server.start();
+
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        server.stop();
+        server.join();
+    }
+
+}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java	Wed Oct 17 19:08:13 2012 +0200
@@ -2,8 +2,11 @@
 
 import java.io.IOException;
 import java.io.Reader;
+import java.io.Writer;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -11,6 +14,8 @@
 
 import com.google.gson.Gson;
 import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.storage.Categories;
+import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Cursor;
 import com.redhat.thermostat.common.storage.Query;
 import com.redhat.thermostat.common.storage.Storage;
@@ -25,15 +30,23 @@
     private Storage storage;
     private Gson gson;
 
+    private int currentCategoryId;
+
+    private Map<String, Integer> categoryIds;
+    private Map<Integer, Category> categories;
+
     public void init() {
-        storage = StorageWrapper.getStorage();
         gson = new Gson();
+        categoryIds = new HashMap<>();
+        categories = new HashMap<>();
     }
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        if (storage == null) {
+            storage = StorageWrapper.getStorage();
+        }
         String uri = req.getRequestURI();
-        System.err.println("request uri: " + uri);
         int lastPartIdx = uri.lastIndexOf("/");
         String cmd = uri.substring(lastPartIdx + 1);
         if (cmd.equals("find-pojo")) {
@@ -42,9 +55,34 @@
             findAll(req, resp);
         } else if (cmd.equals("put-pojo")) {
             putPojo(req, resp);
+        } else if (cmd.equals("register-category")) {
+            registerCategory(req, resp);
         }
     }
 
+    private synchronized void registerCategory(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        String categoryName = req.getParameter("name");
+        String categoryParam = req.getParameter("category");
+        int id;
+        if (categoryIds.containsKey(categoryName)) {
+            id = categoryIds.get(categoryName);
+        } else {
+            // The following has the side effect of registering the newly deserialized Category in the Categories clas.
+            Category category = gson.fromJson(categoryParam, Category.class);
+            storage.registerCategory(category);
+
+            id = currentCategoryId;
+            categoryIds.put(categoryName, id);
+            categories.put(id, category);
+            currentCategoryId++;
+        }
+        resp.setStatus(HttpServletResponse.SC_OK);
+        resp.setContentType("application/json");
+        Writer writer = resp.getWriter();
+        gson.toJson(id, writer);
+        writer.flush();
+    }
+
     private void putPojo(HttpServletRequest req, HttpServletResponse resp) {
         try {
             String insertParam = req.getParameter("insert");
@@ -52,7 +90,9 @@
             Class<? extends Pojo> pojoCls = (Class<? extends Pojo>) Class.forName(insert.getPojoClass());
             String pojoParam = req.getParameter("pojo");
             Pojo pojo = gson.fromJson(pojoParam, pojoCls);
-            storage.putPojo(insert.getCategory(), insert.isReplace(), pojo);
+            int categoryId = insert.getCategoryId();
+            Category category = getCategoryFromId(categoryId);
+            storage.putPojo(category, insert.isReplace(), pojo);
             resp.setStatus(HttpServletResponse.SC_OK);
         } catch (ClassNotFoundException ex) {
             resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
@@ -69,6 +109,7 @@
             Object result = storage.findPojo(targetQuery, resultClass);
             writeResponse(resp, result);
         } catch (ClassNotFoundException e) {
+            e.printStackTrace();
             resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "result class not found");
         }
     }
@@ -87,13 +128,16 @@
             }
             writeResponse(resp, resultList.toArray());
         } catch (ClassNotFoundException e) {
+            e.printStackTrace();
             resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "result class not found");
         }
     }
 
     private Query constructTargetQuery(RESTQuery query) {
         Query targetQuery = storage.createQuery();
-        targetQuery = targetQuery.from(query.getCategory());
+        int categoryId = query.getCategoryId();
+        Category category = getCategoryFromId(categoryId);
+        targetQuery = targetQuery.from(category);
         List<Qualifier<?>> qualifiers = query.getQualifiers();
         for (Qualifier q : qualifiers) {
             targetQuery = targetQuery.where(q.getKey(), q.getCriteria(), q.getValue());
@@ -101,6 +145,11 @@
         return targetQuery;
     }
 
+    private Category getCategoryFromId(int categoryId) {
+        Category category = categories.get(categoryId);
+        return category;
+    }
+
     private void writeResponse(HttpServletResponse resp, Object result) throws IOException {
         resp.setStatus(HttpServletResponse.SC_OK);
         resp.setContentType("application/json");
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java	Tue Oct 16 14:23:29 2012 -0400
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java	Wed Oct 17 19:08:13 2012 +0200
@@ -44,11 +44,16 @@
 import static org.mockito.Mockito.when;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.webapp.WebAppContext;
@@ -59,7 +64,7 @@
 import org.junit.Test;
 
 import com.google.gson.Gson;
-import com.redhat.thermostat.common.model.Pojo;
+import com.redhat.thermostat.common.model.BasePojo;
 import com.redhat.thermostat.common.storage.Categories;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Cursor;
@@ -76,7 +81,7 @@
 
 public class RESTStorageEndpointTest {
 
-    public static class TestClass implements Pojo {
+    public static class TestClass extends BasePojo {
         private String key1;
         private int key2;
         public String getKey1() {
@@ -103,6 +108,7 @@
     private Server server;
     private int port;
     private Storage mockStorage;
+    private Integer categoryId;
 
     private static Key<String> key1;
     private static Key<Integer> key2;
@@ -136,6 +142,7 @@
                 startServer(port);
             }
         });
+        registerCategory();
     }
 
     private void startServer(int port) throws Exception {
@@ -163,6 +170,7 @@
 
         RESTStorage restStorage = new RESTStorage();
         restStorage.setEndpoint(getEndpoint());
+        restStorage.registerCategory(category);
         Query query = restStorage.createQuery();
         query.from(category).where(key1, Criteria.EQUALS, "fluff");
 
@@ -196,7 +204,9 @@
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.setDoInput(true);
         conn.setDoOutput(true);
-        RESTQuery query = (RESTQuery) new RESTQuery().from(category).where(key1, Criteria.EQUALS, "fluff");
+        Map<Category,Integer> categoryIdMap = new HashMap<>();
+        categoryIdMap.put(category, categoryId);
+        RESTQuery query = (RESTQuery) new RESTQuery(categoryIdMap).from(category).where(key1, Criteria.EQUALS, "fluff");
         query.setResultClassName(TestClass.class.getName());
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
@@ -220,11 +230,12 @@
         expected1.setKey2(42);
 
         String endpoint = getEndpoint();
+
         URL url = new URL(endpoint + "/put-pojo");
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        WebInsert insert = new WebInsert(category, true, TestClass.class.getName());
+        WebInsert insert = new WebInsert(categoryId, true, TestClass.class.getName());
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
         out.write("insert=");
@@ -238,6 +249,34 @@
         verify(mockStorage).putPojo(category, true, expected1);
     }
 
+    private void registerCategory() {
+        try {
+            String endpoint = getEndpoint();
+            URL url = new URL(endpoint + "/register-category");
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            String enc = "UTF-8";
+            conn.setRequestProperty("Content-Encoding", enc);
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            conn.setRequestMethod("POST");
+            OutputStream out = conn.getOutputStream();
+            Gson gson = new Gson();
+            OutputStreamWriter writer = new OutputStreamWriter(out);
+            writer.write("name=");
+            writer.write(URLEncoder.encode(category.getName(), enc));
+            writer.write("&category=");
+            writer.write(URLEncoder.encode(gson.toJson(category), enc));
+            writer.flush();
+
+            InputStream in = conn.getInputStream();
+            Reader reader = new InputStreamReader(in);
+            Integer id = gson.fromJson(reader, Integer.class);
+            categoryId = id;
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
     private String getEndpoint() {
         return "http://localhost:" + port + "/storage";
     }