changeset 81:864f75063de2

Move storage classes from agent to common
author Roman Kennke <rkennke@redhat.com>
date Wed, 22 Feb 2012 23:20:13 +0100
parents 29e3172b4ec5
children 71da4a71e1c0
files agent/pom.xml agent/src/main/java/com/redhat/thermostat/agent/Agent.java agent/src/main/java/com/redhat/thermostat/agent/Main.java agent/src/main/java/com/redhat/thermostat/agent/config/ConfigurationWatcher.java agent/src/main/java/com/redhat/thermostat/agent/storage/AgentInformation.java agent/src/main/java/com/redhat/thermostat/agent/storage/BackendInformation.java agent/src/main/java/com/redhat/thermostat/agent/storage/Category.java agent/src/main/java/com/redhat/thermostat/agent/storage/Chunk.java agent/src/main/java/com/redhat/thermostat/agent/storage/ConnectionKey.java agent/src/main/java/com/redhat/thermostat/agent/storage/Key.java agent/src/main/java/com/redhat/thermostat/agent/storage/MongoStorage.java agent/src/main/java/com/redhat/thermostat/agent/storage/Storage.java agent/src/main/java/com/redhat/thermostat/backend/Backend.java agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java agent/src/main/java/com/redhat/thermostat/backend/sample/SampleBackend.java agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java agent/src/test/java/com/redhat/thermostat/agent/AgentTest.java agent/src/test/java/com/redhat/thermostat/agent/storage/BackendInformationTest.java agent/src/test/java/com/redhat/thermostat/agent/storage/MongoStorageTest.java agent/src/test/java/com/redhat/thermostat/agent/storage/StorageTest.java common/pom.xml common/src/main/java/com/redhat/thermostat/common/storage/AgentInformation.java common/src/main/java/com/redhat/thermostat/common/storage/BackendInformation.java common/src/main/java/com/redhat/thermostat/common/storage/Category.java common/src/main/java/com/redhat/thermostat/common/storage/Chunk.java common/src/main/java/com/redhat/thermostat/common/storage/ConnectionKey.java common/src/main/java/com/redhat/thermostat/common/storage/Key.java common/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java common/src/main/java/com/redhat/thermostat/common/storage/Storage.java common/src/test/java/com/redhat/thermostat/common/storage/BackendInformationTest.java common/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java common/src/test/java/com/redhat/thermostat/common/storage/StorageTest.java
diffstat 34 files changed, 1055 insertions(+), 1049 deletions(-) [+]
line wrap: on
line diff
--- a/agent/pom.xml	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/pom.xml	Wed Feb 22 23:20:13 2012 +0100
@@ -70,11 +70,6 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.mongodb</groupId>
-      <artifactId>mongo-java-driver</artifactId>
-      <version>2.7.3</version>
-    </dependency>
-    <dependency>
       <groupId>com.sun</groupId>
       <artifactId>tools</artifactId>
       <version>1.7.0</version>
--- a/agent/src/main/java/com/redhat/thermostat/agent/Agent.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/agent/Agent.java	Wed Feb 22 23:20:13 2012 +0100
@@ -41,12 +41,12 @@
 
 import com.redhat.thermostat.agent.config.ConfigurationWatcher;
 import com.redhat.thermostat.agent.config.StartupConfiguration;
-import com.redhat.thermostat.agent.storage.AgentInformation;
-import com.redhat.thermostat.agent.storage.BackendInformation;
-import com.redhat.thermostat.agent.storage.Storage;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.common.LaunchException;
+import com.redhat.thermostat.common.storage.AgentInformation;
+import com.redhat.thermostat.common.storage.BackendInformation;
+import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 /**
--- a/agent/src/main/java/com/redhat/thermostat/agent/Main.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/agent/Main.java	Wed Feb 22 23:20:13 2012 +0100
@@ -45,12 +45,12 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.agent.config.StartupConfiguration;
-import com.redhat.thermostat.agent.storage.MongoStorage;
-import com.redhat.thermostat.agent.storage.Storage;
 import com.redhat.thermostat.backend.BackendLoadException;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.common.Constants;
 import com.redhat.thermostat.common.LaunchException;
+import com.redhat.thermostat.common.storage.MongoStorage;
+import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 public final class Main {
--- a/agent/src/main/java/com/redhat/thermostat/agent/config/ConfigurationWatcher.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/agent/config/ConfigurationWatcher.java	Wed Feb 22 23:20:13 2012 +0100
@@ -38,8 +38,8 @@
 
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.storage.Storage;
 import com.redhat.thermostat.backend.BackendRegistry;
+import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 public class ConfigurationWatcher implements Runnable {
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/AgentInformation.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +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.agent.storage;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class AgentInformation {
-
-    private long startTime;
-    private List<BackendInformation> backends = new ArrayList<BackendInformation>();
-
-    public long getStartTime() {
-        return startTime;
-    }
-
-    public void setStartTime(long startTime) {
-        this.startTime = startTime;
-    }
-
-    public List<BackendInformation> getBackends() {
-        return Collections.unmodifiableList(backends);
-    }
-
-    public void addBackend(BackendInformation backend) {
-        backends.add(backend);
-    }
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/BackendInformation.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +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.agent.storage;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class BackendInformation {
-
-    private String name;
-    private String description;
-    private boolean observeNewJvm;
-    private List<Integer> pids;
-    private Map<String, String> configuration = new HashMap<String,String>();
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public boolean isObserveNewJvm() {
-        return observeNewJvm;
-    }
-
-    public void setObserveNewJvm(boolean observeNewJvm) {
-        this.observeNewJvm = observeNewJvm;
-    }
-
-    public List<Integer> getPids() {
-        return pids;
-    }
-
-    public Map<String, String> getConfiguration() {
-        return configuration;
-    }
-
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/Category.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +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.agent.storage;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-public class Category {
-    private final String name;
-    private final List<Key> keys;
-    private boolean locked = false;
-
-    private ConnectionKey connectionKey;
-
-    private static Set<String> categoryNames = new HashSet<String>();
-
-    /**
-     * Creates a new Category instance with the specified name.
-     *
-     * @param name the name of the category
-     *
-     * @throws IllegalArgumentException if a Category is created with a name that has been used before
-     */
-    public Category(String name) {
-        if (categoryNames.contains(name)) {
-            throw new IllegalStateException();
-        }
-        categoryNames.add(name);
-        this.name = name;
-        keys = new ArrayList<Key>();
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public synchronized void lock() {
-        locked = true;
-    }
-
-    public synchronized void addKey(Key key) {
-        if (!locked) {
-            keys.add(key);
-        } else {
-            throw new IllegalStateException("Once locked, a category's keys may not be changed.");
-        }
-    }
-
-    public synchronized Iterator<Key> getEntryIterator() {
-        return keys.iterator();
-    }
-
-    public void setConnectionKey(ConnectionKey connKey) {
-        connectionKey = connKey;
-    }
-
-    public ConnectionKey getConnectionKey() {
-        return connectionKey;
-    }
-
-    public boolean hasBeenRegistered() {
-        return getConnectionKey() != null;
-    }
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/Chunk.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +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.agent.storage;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A Chunk is a unit containing a set of data that can be added as a whole to the dataset
- * that exists behind the storage layer.
- */
-public class Chunk {
-    private final Category category;
-    private final boolean replace;
-
-    private Map<Key, String> values = new HashMap<Key, String>();
-
-    /**
-     * 
-     * @param timestamp The time that should be associated with the data in this nugget.
-     * @param category The {@link Category} of this data.  This should be a Category that the {@link Backend}
-     * who is producing this Chunk has registered via {@link Storage#registerCategory()}
-     * @param add whether this chunk should replace the values based on the keys for this category,
-     * or be added to a set of values in this category
-     */
-    public Chunk(Category category, boolean replace) {
-        this.category = category;
-        this.replace = replace;
-    }
-
-    public Category getCategory() {
-        return category;
-    }
-
-    public boolean getReplace() {
-        return replace;
-    }
-
-    public void put(Key entry, String value) {
-        values.put(entry, value);
-    }
-
-    public String get(Key entry) {
-        return values.get(entry);
-    }
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/ConnectionKey.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +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.agent.storage;
-
-public interface ConnectionKey {
-
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/Key.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.agent.storage;
-
-/**
- * A Key is used to refer to data in a {@link Chunk}.  It may also be a partial key to the
- * set of data represented by a {@link Chunk} in a category.
- */
-public class Key {
-
-    // Key used by most Categories.
-    public static Key TIMESTAMP = new Key("timestamp", false);
-
-    private String name;
-    private boolean isPartialCategoryKey;
-
-    public Key(String name, boolean isPartialCategoryKey) {
-        this.name = name;
-        this.isPartialCategoryKey = isPartialCategoryKey;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public boolean isPartialCategoryKey() {
-        return isPartialCategoryKey;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if ((o == null) || (o.getClass() != this.getClass())) {
-            return false;
-        }
-        Key e = (Key) o;
-        return (isPartialCategoryKey == e.isPartialCategoryKey()) &&
-            name.equals(e.getName());
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 1867;
-        hash = hash * 37 + (isPartialCategoryKey ? 0 : 1);
-        hash = hash * 37 + (name == null ? 0 : name.hashCode());
-        return hash;
-    }
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/MongoStorage.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,295 +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.agent.storage;
-
-import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.UUID;
-
-import org.bson.BSONObject;
-
-import com.mongodb.BasicDBList;
-import com.mongodb.BasicDBObject;
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBObject;
-import com.mongodb.Mongo;
-import com.mongodb.MongoURI;
-import com.mongodb.WriteConcern;
-import com.redhat.thermostat.common.storage.StorageConstants;
-
-/**
- * Implementation of the Storage interface that uses MongoDB to store the instrumentation data.
- * 
- * In this implementation, each CATEGORY is given a distinct collection.
- */
-public class MongoStorage extends Storage {
-
-    public static final String KEY_AGENT_ID = "agent-id";
-    public static final String SET_MODIFIER = "$set";
-
-    private Mongo mongo = null;
-    private DB db = null;
-    private Map<String, DBCollection> collectionCache = new HashMap<String, DBCollection>();
-
-    private UUID agentId = null;
-
-    @Override
-    public void connect(String uri) throws UnknownHostException {
-        connect(new MongoURI(uri));
-    }
-
-    private void connect(MongoURI uri) throws UnknownHostException {
-        mongo = new Mongo(uri);
-        db = mongo.getDB(StorageConstants.THERMOSTAT_DB_NAME);
-    }
-
-    @Override
-    public void setAgentId(UUID agentId) {
-        this.agentId = agentId;
-    }
-
-    @Override
-    public void addAgentInformation(AgentInformation agentInfo) {
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        DBObject toInsert = createConfigDBObject(agentInfo);
-        /* cast required to disambiguate between putAll(BSONObject) and putAll(Map) */
-        toInsert.putAll((BSONObject) getAgentDBObject());
-        configCollection.insert(toInsert, WriteConcern.SAFE);
-    }
-
-    @Override
-    public void removeAgentInformation() {
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        BasicDBObject toRemove = getAgentDBObject();
-        configCollection.remove(toRemove, WriteConcern.NORMAL);
-    }
-
-    @Override
-    public String getBackendConfig(String backendName, String configurationKey) {
-        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
-        BasicDBObject query = getAgentDBObject();
-        query.put(StorageConstants.KEY_AGENT_CONFIG_BACKENDS + "." + backendName, new BasicDBObject("$exists", true));
-        DBObject config = configCollection.findOne(query);
-        Object value = config.get(configurationKey);
-        if (value instanceof String) {
-            return (String) value;
-        }
-        return null;
-    }
-
-    private BasicDBObject getAgentDBObject() {
-        return new BasicDBObject(KEY_AGENT_ID, agentId.toString());
-    }
-
-    @Override
-    public void putChunk(Chunk chunk) {
-        Category cat = chunk.getCategory();
-        DBCollection coll = getCachedCollection(cat.getName());
-        BasicDBObject toInsert = getAgentDBObject();
-        BasicDBObject replaceKey = null;
-        boolean replace = chunk.getReplace();
-        Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
-        Map<String, BasicDBObject> replaceKeyNestedParts = null;
-        if (replace) {
-            replaceKey = getAgentDBObject();
-            replaceKeyNestedParts = new HashMap<String, BasicDBObject>();
-        }
-        for (Iterator<com.redhat.thermostat.agent.storage.Key> iter = cat.getEntryIterator(); iter.hasNext();) {
-            com.redhat.thermostat.agent.storage.Key key = iter.next();
-            boolean isKey = key.isPartialCategoryKey();
-            String[] entryParts = key.getName().split("\\.");
-            if (entryParts.length == 2) {
-                BasicDBObject nested = nestedParts.get(entryParts[0]);
-                if (nested == null) {
-                    if (isKey) {
-                        throwMissingKey(key.getName());
-                    }
-                    nested = new BasicDBObject();
-                    nestedParts.put(entryParts[0], nested);
-                }
-                nested.append(entryParts[1], chunk.get(key));
-                if (replace && isKey) {
-                    BasicDBObject replaceKeyNested = replaceKeyNestedParts.get(entryParts[0]);
-                    if (replaceKeyNested == null) {
-                        replaceKeyNested = new BasicDBObject();
-                        replaceKeyNestedParts.put(entryParts[0], replaceKeyNested);
-                    }
-                    replaceKeyNested.append(entryParts[1], replaceKeyNested);
-                }
-            } else {
-                String mongoKey = key.getName();
-                String value = chunk.get(key);
-                if ((value == null) && isKey) {
-                    throwMissingKey(key.getName());
-                }
-                toInsert.append(mongoKey, value);
-                if (replace && isKey) {
-                    replaceKey.append(mongoKey, value);
-                }
-            }
-        }
-        for (String mongoKey : nestedParts.keySet()) {
-            toInsert.append(mongoKey, nestedParts.get(mongoKey));
-        }
-        if (replace) {
-            for (String mongoKey : replaceKeyNestedParts.keySet()) {
-                replaceKey.append(mongoKey, replaceKeyNestedParts.get(mongoKey));
-            }
-            coll.update(replaceKey, toInsert, true, false);
-        } else {
-            coll.insert(toInsert);
-        }
-    }
-
-    @Override
-    public void updateChunk(Chunk chunk) {
-        Category cat = chunk.getCategory();
-        DBCollection coll = getCachedCollection(cat.getName());
-        BasicDBObject toUpdate = new BasicDBObject();
-        BasicDBObject updateKey = getAgentDBObject();
-        Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
-        Map<String, BasicDBObject> updateKeyNestedParts = new HashMap<String, BasicDBObject>();
-        for (Iterator<com.redhat.thermostat.agent.storage.Key> iter = cat.getEntryIterator(); iter.hasNext();) {
-            com.redhat.thermostat.agent.storage.Key key = iter.next();
-            boolean isKey = key.isPartialCategoryKey();
-            String[] entryParts = key.getName().split("\\.");
-            if (entryParts.length == 2) {
-                BasicDBObject nested = nestedParts.get(entryParts[0]);
-                if (nested == null) {
-                    if (isKey) {
-                        throwMissingKey(key.getName());
-                    }
-                } else {
-                    if (isKey) {
-                        BasicDBObject updateKeyNested = updateKeyNestedParts.get(entryParts[0]);
-                        if (updateKeyNested == null) {
-                            updateKeyNested = new BasicDBObject();
-                            updateKeyNestedParts.put(entryParts[0], updateKeyNested);
-                        }
-                        updateKeyNested.append(entryParts[1], updateKeyNested);
-                    } else {
-                        nested.append(SET_MODIFIER, new BasicDBObject(entryParts[1], chunk.get(key)));
-                    }
-                }
-            } else {
-                String mongoKey = key.getName();
-                String value = chunk.get(key);
-                if (value == null) {
-                    if (isKey) {
-                        throwMissingKey(key.getName());
-                    }
-                } else {
-                    if (isKey) {
-                        updateKey.append(mongoKey, value);
-                    } else {
-                        toUpdate.append(SET_MODIFIER, new BasicDBObject(mongoKey, value));
-                    }
-                }
-            }
-        }
-        for (String mongoKey : nestedParts.keySet()) {
-            toUpdate.append(mongoKey, nestedParts.get(mongoKey));
-        }
-        for (String mongoKey : updateKeyNestedParts.keySet()) {
-            updateKey.append(mongoKey, updateKeyNestedParts.get(mongoKey));
-        }
-        coll.update(updateKey, toUpdate);
-    }
-
-    private void throwMissingKey(String keyName) {
-        throw new IllegalArgumentException("Attempt to insert chunk with incomplete partial key.  Missing: " + keyName);
-    }
-
-    private DBCollection getCachedCollection(String collName) {
-        DBCollection coll = collectionCache.get(collName);
-        if (coll == null) {
-            coll = db.getCollection(collName);
-            if (coll != null) {
-                collectionCache.put(collName, coll);
-            }
-        }
-        return coll;
-    }
-
-    private DBObject createConfigDBObject(AgentInformation agentInfo) {
-        BasicDBObject result = getAgentDBObject();
-        result.put(StorageConstants.KEY_AGENT_CONFIG_AGENT_START_TIME, agentInfo.getStartTime());
-        BasicDBObject backends = new BasicDBObject();
-        for (BackendInformation backend : agentInfo.getBackends()) {
-            backends.put(backend.getName(), createBackendConfigDBObject(backend));
-        }
-        result.put(StorageConstants.KEY_AGENT_CONFIG_BACKENDS, backends);
-        return result;
-    }
-
-    private DBObject createBackendConfigDBObject(BackendInformation backend) {
-        BasicDBObject result = new BasicDBObject();
-        Map<String, String> configMap = backend.getConfiguration();
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_NAME, backend.getName());
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_DESC, backend.getDescription());
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_ACTIVE, createBackendActiveDBObject(backend));
-        for (String configName : configMap.keySet()) {
-            result.append(configName, configMap.get(configName));
-        }
-        return result;
-    }
-
-    private DBObject createBackendActiveDBObject(BackendInformation backend) {
-        BasicDBObject result = new BasicDBObject();
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_NEW, backend.isObserveNewJvm());
-        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_PIDS, new BasicDBList());
-        // TODO check which processes are already being listened to.
-        return result;
-    }
-
-    public void purge() {
-        BasicDBObject deleteKey = getAgentDBObject();
-        for (DBCollection coll : collectionCache.values()) {
-            coll.remove(deleteKey);
-        }
-    }
-
-    @Override
-    public ConnectionKey createConnectionKey(Category category) {
-        // 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(){};
-    }
-}
--- a/agent/src/main/java/com/redhat/thermostat/agent/storage/Storage.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +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.agent.storage;
-
-import java.net.UnknownHostException;
-import java.util.UUID;
-
-public abstract class Storage {
-
-    public abstract void connect(String uri) throws UnknownHostException;
-
-    public abstract void setAgentId(UUID id);
-
-    public abstract void addAgentInformation(AgentInformation agentInfo);
-
-    public abstract void removeAgentInformation();
-
-    /**
-     * @return {@code null} if the value is invalid or missing
-     */
-    public abstract String getBackendConfig(String backendName, String configurationKey);
-
-    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 ConnectionKey createConnectionKey(Category category);
-
-    public abstract void putChunk(Chunk chunk);
-
-    public abstract void updateChunk(Chunk chunk);
-
-    /* Drop all data related to the currently running agent.
-     */
-    public abstract void purge();
-
-}
--- a/agent/src/main/java/com/redhat/thermostat/backend/Backend.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/backend/Backend.java	Wed Feb 22 23:20:13 2012 +0100
@@ -41,9 +41,10 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
-import com.redhat.thermostat.agent.storage.Category;
-import com.redhat.thermostat.agent.storage.Chunk;
-import com.redhat.thermostat.agent.storage.Storage;
+import com.redhat.thermostat.common.LaunchException;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Storage;
 
 /**
  * Represents a monitoring back-end. All the {@link Backend}s should be
--- a/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java	Wed Feb 22 23:20:13 2012 +0100
@@ -43,9 +43,9 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.storage.Storage;
 import com.redhat.thermostat.agent.config.StartupConfiguration;
 import com.redhat.thermostat.backend.system.SystemBackend;
+import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 /**
--- a/agent/src/main/java/com/redhat/thermostat/backend/sample/SampleBackend.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/backend/sample/SampleBackend.java	Wed Feb 22 23:20:13 2012 +0100
@@ -43,8 +43,8 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.agent.storage.Category;
 import com.redhat.thermostat.backend.Backend;
+import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 /** Just an example backend implementation.  This is really just to test the loading and configuration mechanisms
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Wed Feb 22 23:20:13 2012 +0100
@@ -57,10 +57,10 @@
 
 import com.redhat.thermostat.agent.JvmStatusListener;
 import com.redhat.thermostat.agent.JvmStatusNotifier;
-import com.redhat.thermostat.agent.storage.Category;
-import com.redhat.thermostat.agent.storage.Chunk;
-import com.redhat.thermostat.agent.storage.Key;
 import com.redhat.thermostat.common.VmInfo;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 public class JvmStatHostListener implements HostListener, JvmStatusNotifier {
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Wed Feb 22 23:20:13 2012 +0100
@@ -48,13 +48,13 @@
 import sun.jvmstat.monitor.event.VmEvent;
 import sun.jvmstat.monitor.event.VmListener;
 
-import com.redhat.thermostat.agent.storage.Category;
-import com.redhat.thermostat.agent.storage.Chunk;
-import com.redhat.thermostat.agent.storage.Key;
 import com.redhat.thermostat.common.VmGcStat;
 import com.redhat.thermostat.common.VmMemoryStat;
 import com.redhat.thermostat.common.VmMemoryStat.Generation;
 import com.redhat.thermostat.common.VmMemoryStat.Space;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 public class JvmStatVmListener implements VmListener {
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Wed Feb 22 23:20:13 2012 +0100
@@ -53,15 +53,15 @@
 
 import com.redhat.thermostat.agent.JvmStatusListener;
 import com.redhat.thermostat.agent.JvmStatusNotifier;
-import com.redhat.thermostat.agent.storage.Category;
-import com.redhat.thermostat.agent.storage.Chunk;
-import com.redhat.thermostat.agent.storage.Key;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.common.CpuStat;
 import com.redhat.thermostat.common.HostInfo;
 import com.redhat.thermostat.common.MemoryStat;
 import com.redhat.thermostat.common.NetworkInterfaceInfo;
 import com.redhat.thermostat.common.VmCpuStat;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 
 public class SystemBackend extends Backend implements JvmStatusNotifier, JvmStatusListener {
--- a/agent/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Wed Feb 22 23:08:08 2012 +0100
+++ b/agent/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Wed Feb 22 23:20:13 2012 +0100
@@ -49,11 +49,11 @@
 import org.mockito.ArgumentCaptor;
 
 import com.redhat.thermostat.agent.config.StartupConfiguration;
-import com.redhat.thermostat.agent.storage.AgentInformation;
-import com.redhat.thermostat.agent.storage.BackendInformation;
-import com.redhat.thermostat.agent.storage.Storage;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendRegistry;
+import com.redhat.thermostat.common.storage.AgentInformation;
+import com.redhat.thermostat.common.storage.BackendInformation;
+import com.redhat.thermostat.common.storage.Storage;
 
 public class AgentTest {
 
--- a/agent/src/test/java/com/redhat/thermostat/agent/storage/BackendInformationTest.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +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.agent.storage;
-
-import static org.junit.Assert.assertNotNull;
-
-import java.util.Map;
-
-import org.junit.Test;
-
-public class BackendInformationTest {
-
-    @Test
-    public void testConfigurationNotNull() {
-        BackendInformation backendInfo = new BackendInformation();
-        Map<String,String> config = backendInfo.getConfiguration();
-        assertNotNull(config);
-    }
-
-}
--- a/agent/src/test/java/com/redhat/thermostat/agent/storage/MongoStorageTest.java	Wed Feb 22 23:08:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +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.agent.storage;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Test;
-
-public class MongoStorageTest {
-
-    @Test
-    public void testCreateConnectionKey() {
-        MongoStorage mongoStorage = new MongoStorage();
-        Category category = new Category("testCreateConnectionKey");
-        ConnectionKey connKey = mongoStorage.createConnectionKey(category);
-        assertNotNull(connKey);
-    }
-
-}
--- a/agent/src/test/java/com/redhat/thermostat/agent/storage/StorageTest.java	Wed Feb 22 23:08:08 2012 +0100
+++ /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.agent.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/common/pom.xml	Wed Feb 22 23:08:08 2012 +0100
+++ b/common/pom.xml	Wed Feb 22 23:20:13 2012 +0100
@@ -58,6 +58,17 @@
       <version>4.10</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.9.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mongodb</groupId>
+      <artifactId>mongo-java-driver</artifactId>
+      <version>2.7.3</version>
+    </dependency>
   </dependencies>
 
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/AgentInformation.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,63 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class AgentInformation {
+
+    private long startTime;
+    private List<BackendInformation> backends = new ArrayList<BackendInformation>();
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(long startTime) {
+        this.startTime = startTime;
+    }
+
+    public List<BackendInformation> getBackends() {
+        return Collections.unmodifiableList(backends);
+    }
+
+    public void addBackend(BackendInformation backend) {
+        backends.add(backend);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/BackendInformation.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,83 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class BackendInformation {
+
+    private String name;
+    private String description;
+    private boolean observeNewJvm;
+    private List<Integer> pids;
+    private Map<String, String> configuration = new HashMap<String,String>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public boolean isObserveNewJvm() {
+        return observeNewJvm;
+    }
+
+    public void setObserveNewJvm(boolean observeNewJvm) {
+        this.observeNewJvm = observeNewJvm;
+    }
+
+    public List<Integer> getPids() {
+        return pids;
+    }
+
+    public Map<String, String> getConfiguration() {
+        return configuration;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Category.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,101 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public class Category {
+    private final String name;
+    private final List<Key> keys;
+    private boolean locked = false;
+
+    private ConnectionKey connectionKey;
+
+    private static Set<String> categoryNames = new HashSet<String>();
+
+    /**
+     * Creates a new Category instance with the specified name.
+     *
+     * @param name the name of the category
+     *
+     * @throws IllegalArgumentException if a Category is created with a name that has been used before
+     */
+    public Category(String name) {
+        if (categoryNames.contains(name)) {
+            throw new IllegalStateException();
+        }
+        categoryNames.add(name);
+        this.name = name;
+        keys = new ArrayList<Key>();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public synchronized void lock() {
+        locked = true;
+    }
+
+    public synchronized void addKey(Key key) {
+        if (!locked) {
+            keys.add(key);
+        } else {
+            throw new IllegalStateException("Once locked, a category's keys may not be changed.");
+        }
+    }
+
+    public synchronized Iterator<Key> getEntryIterator() {
+        return keys.iterator();
+    }
+
+    public void setConnectionKey(ConnectionKey connKey) {
+        connectionKey = connKey;
+    }
+
+    public ConnectionKey getConnectionKey() {
+        return connectionKey;
+    }
+
+    public boolean hasBeenRegistered() {
+        return getConnectionKey() != null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Chunk.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,80 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A Chunk is a unit containing a set of data that can be added as a whole to the dataset
+ * that exists behind the storage layer.
+ */
+public class Chunk {
+    private final Category category;
+    private final boolean replace;
+
+    private Map<Key, String> values = new HashMap<Key, String>();
+
+    /**
+     * 
+     * @param timestamp The time that should be associated with the data in this nugget.
+     * @param category The {@link Category} of this data.  This should be a Category that the {@link Backend}
+     * who is producing this Chunk has registered via {@link Storage#registerCategory()}
+     * @param add whether this chunk should replace the values based on the keys for this category,
+     * or be added to a set of values in this category
+     */
+    public Chunk(Category category, boolean replace) {
+        this.category = category;
+        this.replace = replace;
+    }
+
+    public Category getCategory() {
+        return category;
+    }
+
+    public boolean getReplace() {
+        return replace;
+    }
+
+    public void put(Key entry, String value) {
+        values.put(entry, value);
+    }
+
+    public String get(Key entry) {
+        return values.get(entry);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/ConnectionKey.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+public interface ConnectionKey {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Key.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+/**
+ * A Key is used to refer to data in a {@link Chunk}.  It may also be a partial key to the
+ * set of data represented by a {@link Chunk} in a category.
+ */
+public class Key {
+
+    // Key used by most Categories.
+    public static Key TIMESTAMP = new Key("timestamp", false);
+
+    private String name;
+    private boolean isPartialCategoryKey;
+
+    public Key(String name, boolean isPartialCategoryKey) {
+        this.name = name;
+        this.isPartialCategoryKey = isPartialCategoryKey;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isPartialCategoryKey() {
+        return isPartialCategoryKey;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if ((o == null) || (o.getClass() != this.getClass())) {
+            return false;
+        }
+        Key e = (Key) o;
+        return (isPartialCategoryKey == e.isPartialCategoryKey()) &&
+            name.equals(e.getName());
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 1867;
+        hash = hash * 37 + (isPartialCategoryKey ? 0 : 1);
+        hash = hash * 37 + (name == null ? 0 : name.hashCode());
+        return hash;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,294 @@
+/*
+ * 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 java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+
+import org.bson.BSONObject;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.Mongo;
+import com.mongodb.MongoURI;
+import com.mongodb.WriteConcern;
+
+/**
+ * Implementation of the Storage interface that uses MongoDB to store the instrumentation data.
+ * 
+ * In this implementation, each CATEGORY is given a distinct collection.
+ */
+public class MongoStorage extends Storage {
+
+    public static final String KEY_AGENT_ID = "agent-id";
+    public static final String SET_MODIFIER = "$set";
+
+    private Mongo mongo = null;
+    private DB db = null;
+    private Map<String, DBCollection> collectionCache = new HashMap<String, DBCollection>();
+
+    private UUID agentId = null;
+
+    @Override
+    public void connect(String uri) throws UnknownHostException {
+        connect(new MongoURI(uri));
+    }
+
+    private void connect(MongoURI uri) throws UnknownHostException {
+        mongo = new Mongo(uri);
+        db = mongo.getDB(StorageConstants.THERMOSTAT_DB_NAME);
+    }
+
+    @Override
+    public void setAgentId(UUID agentId) {
+        this.agentId = agentId;
+    }
+
+    @Override
+    public void addAgentInformation(AgentInformation agentInfo) {
+        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
+        DBObject toInsert = createConfigDBObject(agentInfo);
+        /* cast required to disambiguate between putAll(BSONObject) and putAll(Map) */
+        toInsert.putAll((BSONObject) getAgentDBObject());
+        configCollection.insert(toInsert, WriteConcern.SAFE);
+    }
+
+    @Override
+    public void removeAgentInformation() {
+        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
+        BasicDBObject toRemove = getAgentDBObject();
+        configCollection.remove(toRemove, WriteConcern.NORMAL);
+    }
+
+    @Override
+    public String getBackendConfig(String backendName, String configurationKey) {
+        DBCollection configCollection = db.getCollection(StorageConstants.CATEGORY_AGENT_CONFIG);
+        BasicDBObject query = getAgentDBObject();
+        query.put(StorageConstants.KEY_AGENT_CONFIG_BACKENDS + "." + backendName, new BasicDBObject("$exists", true));
+        DBObject config = configCollection.findOne(query);
+        Object value = config.get(configurationKey);
+        if (value instanceof String) {
+            return (String) value;
+        }
+        return null;
+    }
+
+    private BasicDBObject getAgentDBObject() {
+        return new BasicDBObject(KEY_AGENT_ID, agentId.toString());
+    }
+
+    @Override
+    public void putChunk(Chunk chunk) {
+        Category cat = chunk.getCategory();
+        DBCollection coll = getCachedCollection(cat.getName());
+        BasicDBObject toInsert = getAgentDBObject();
+        BasicDBObject replaceKey = null;
+        boolean replace = chunk.getReplace();
+        Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
+        Map<String, BasicDBObject> replaceKeyNestedParts = null;
+        if (replace) {
+            replaceKey = getAgentDBObject();
+            replaceKeyNestedParts = new HashMap<String, BasicDBObject>();
+        }
+        for (Iterator<Key> iter = cat.getEntryIterator(); iter.hasNext();) {
+            Key key = iter.next();
+            boolean isKey = key.isPartialCategoryKey();
+            String[] entryParts = key.getName().split("\\.");
+            if (entryParts.length == 2) {
+                BasicDBObject nested = nestedParts.get(entryParts[0]);
+                if (nested == null) {
+                    if (isKey) {
+                        throwMissingKey(key.getName());
+                    }
+                    nested = new BasicDBObject();
+                    nestedParts.put(entryParts[0], nested);
+                }
+                nested.append(entryParts[1], chunk.get(key));
+                if (replace && isKey) {
+                    BasicDBObject replaceKeyNested = replaceKeyNestedParts.get(entryParts[0]);
+                    if (replaceKeyNested == null) {
+                        replaceKeyNested = new BasicDBObject();
+                        replaceKeyNestedParts.put(entryParts[0], replaceKeyNested);
+                    }
+                    replaceKeyNested.append(entryParts[1], replaceKeyNested);
+                }
+            } else {
+                String mongoKey = key.getName();
+                String value = chunk.get(key);
+                if ((value == null) && isKey) {
+                    throwMissingKey(key.getName());
+                }
+                toInsert.append(mongoKey, value);
+                if (replace && isKey) {
+                    replaceKey.append(mongoKey, value);
+                }
+            }
+        }
+        for (String mongoKey : nestedParts.keySet()) {
+            toInsert.append(mongoKey, nestedParts.get(mongoKey));
+        }
+        if (replace) {
+            for (String mongoKey : replaceKeyNestedParts.keySet()) {
+                replaceKey.append(mongoKey, replaceKeyNestedParts.get(mongoKey));
+            }
+            coll.update(replaceKey, toInsert, true, false);
+        } else {
+            coll.insert(toInsert);
+        }
+    }
+
+    @Override
+    public void updateChunk(Chunk chunk) {
+        Category cat = chunk.getCategory();
+        DBCollection coll = getCachedCollection(cat.getName());
+        BasicDBObject toUpdate = new BasicDBObject();
+        BasicDBObject updateKey = getAgentDBObject();
+        Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
+        Map<String, BasicDBObject> updateKeyNestedParts = new HashMap<String, BasicDBObject>();
+        for (Iterator<Key> iter = cat.getEntryIterator(); iter.hasNext();) {
+            Key key = iter.next();
+            boolean isKey = key.isPartialCategoryKey();
+            String[] entryParts = key.getName().split("\\.");
+            if (entryParts.length == 2) {
+                BasicDBObject nested = nestedParts.get(entryParts[0]);
+                if (nested == null) {
+                    if (isKey) {
+                        throwMissingKey(key.getName());
+                    }
+                } else {
+                    if (isKey) {
+                        BasicDBObject updateKeyNested = updateKeyNestedParts.get(entryParts[0]);
+                        if (updateKeyNested == null) {
+                            updateKeyNested = new BasicDBObject();
+                            updateKeyNestedParts.put(entryParts[0], updateKeyNested);
+                        }
+                        updateKeyNested.append(entryParts[1], updateKeyNested);
+                    } else {
+                        nested.append(SET_MODIFIER, new BasicDBObject(entryParts[1], chunk.get(key)));
+                    }
+                }
+            } else {
+                String mongoKey = key.getName();
+                String value = chunk.get(key);
+                if (value == null) {
+                    if (isKey) {
+                        throwMissingKey(key.getName());
+                    }
+                } else {
+                    if (isKey) {
+                        updateKey.append(mongoKey, value);
+                    } else {
+                        toUpdate.append(SET_MODIFIER, new BasicDBObject(mongoKey, value));
+                    }
+                }
+            }
+        }
+        for (String mongoKey : nestedParts.keySet()) {
+            toUpdate.append(mongoKey, nestedParts.get(mongoKey));
+        }
+        for (String mongoKey : updateKeyNestedParts.keySet()) {
+            updateKey.append(mongoKey, updateKeyNestedParts.get(mongoKey));
+        }
+        coll.update(updateKey, toUpdate);
+    }
+
+    private void throwMissingKey(String keyName) {
+        throw new IllegalArgumentException("Attempt to insert chunk with incomplete partial key.  Missing: " + keyName);
+    }
+
+    private DBCollection getCachedCollection(String collName) {
+        DBCollection coll = collectionCache.get(collName);
+        if (coll == null) {
+            coll = db.getCollection(collName);
+            if (coll != null) {
+                collectionCache.put(collName, coll);
+            }
+        }
+        return coll;
+    }
+
+    private DBObject createConfigDBObject(AgentInformation agentInfo) {
+        BasicDBObject result = getAgentDBObject();
+        result.put(StorageConstants.KEY_AGENT_CONFIG_AGENT_START_TIME, agentInfo.getStartTime());
+        BasicDBObject backends = new BasicDBObject();
+        for (BackendInformation backend : agentInfo.getBackends()) {
+            backends.put(backend.getName(), createBackendConfigDBObject(backend));
+        }
+        result.put(StorageConstants.KEY_AGENT_CONFIG_BACKENDS, backends);
+        return result;
+    }
+
+    private DBObject createBackendConfigDBObject(BackendInformation backend) {
+        BasicDBObject result = new BasicDBObject();
+        Map<String, String> configMap = backend.getConfiguration();
+        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_NAME, backend.getName());
+        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_DESC, backend.getDescription());
+        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_ACTIVE, createBackendActiveDBObject(backend));
+        for (String configName : configMap.keySet()) {
+            result.append(configName, configMap.get(configName));
+        }
+        return result;
+    }
+
+    private DBObject createBackendActiveDBObject(BackendInformation backend) {
+        BasicDBObject result = new BasicDBObject();
+        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_NEW, backend.isObserveNewJvm());
+        result.append(StorageConstants.KEY_AGENT_CONFIG_BACKEND_PIDS, new BasicDBList());
+        // TODO check which processes are already being listened to.
+        return result;
+    }
+
+    public void purge() {
+        BasicDBObject deleteKey = getAgentDBObject();
+        for (DBCollection coll : collectionCache.values()) {
+            coll.remove(deleteKey);
+        }
+    }
+
+    @Override
+    public ConnectionKey createConnectionKey(Category category) {
+        // 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(){};
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,75 @@
+/*
+ * 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 java.net.UnknownHostException;
+import java.util.UUID;
+
+public abstract class Storage {
+
+    public abstract void connect(String uri) throws UnknownHostException;
+
+    public abstract void setAgentId(UUID id);
+
+    public abstract void addAgentInformation(AgentInformation agentInfo);
+
+    public abstract void removeAgentInformation();
+
+    /**
+     * @return {@code null} if the value is invalid or missing
+     */
+    public abstract String getBackendConfig(String backendName, String configurationKey);
+
+    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 ConnectionKey createConnectionKey(Category category);
+
+    public abstract void putChunk(Chunk chunk);
+
+    public abstract void updateChunk(Chunk chunk);
+
+    /* Drop all data related to the currently running agent.
+     */
+    public abstract void purge();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/common/storage/BackendInformationTest.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,54 @@
+/*
+ * 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.assertNotNull;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+public class BackendInformationTest {
+
+    @Test
+    public void testConfigurationNotNull() {
+        BackendInformation backendInfo = new BackendInformation();
+        Map<String,String> config = backendInfo.getConfiguration();
+        assertNotNull(config);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,53 @@
+/*
+ * 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.assertNotNull;
+
+import org.junit.Test;
+
+public class MongoStorageTest {
+
+    @Test
+    public void testCreateConnectionKey() {
+        MongoStorage mongoStorage = new MongoStorage();
+        Category category = new Category("testCreateConnectionKey");
+        ConnectionKey connKey = mongoStorage.createConnectionKey(category);
+        assertNotNull(connKey);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/common/storage/StorageTest.java	Wed Feb 22 23:20:13 2012 +0100
@@ -0,0 +1,92 @@
+/*
+ * 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);
+    }
+}