changeset 2289:fa7923c23a0e

Add storage-populator command Reviewed-by: jerboaa, neugens, omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-April/018609.html
author James Aziz <jaziz@redhat.com>
date Thu, 05 May 2016 10:37:43 -0400
parents 96940b61b718
children f0e974d6bf67
files dev/data-populator/example-configs/population-config-example-simple-threads.json dev/data-populator/example-configs/population-config-example-simple-vm-deadlock.json dev/data-populator/example-configs/population-config-example-simple.json dev/data-populator/pom.xml dev/data-populator/scripts/populate dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/Arguments.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/CollectionPopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/ConnectionEstablisher.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/Main.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/StoragePopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/ConfigItem.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/PopulationConfig.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/ConfigItemTypeAdapter.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/NotImplementedException.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/PopulationConfigTypeAdapter.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/PopulationConfigTypeAdapterFactory.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/RelationShipTypeAdapter.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/dependencies/ProcessedRecords.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/dependencies/Relationship.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/dependencies/SharedState.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/AgentInfoPopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/BasePopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/HostInfoPopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/NetworkInfoPopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/ThreadPopulator.java dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/VmInfoPopulator.java dev/data-populator/src/main/resources/META-INF/services/com.redhat.thermostat.dev.populator.CollectionPopulator dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/ArgumentsTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/PopulationConfigTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/typeadapter/ConfigItemTypeAdapterTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/typeadapter/PopulationConfigTypeAdapterTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/typeadapter/RelationShipTypeAdapterTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/dependencies/RelationshipTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/AgentInfoPopulatorTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/HostInfoPopulatorTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/NetworkInfoPopulatorTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/ThreadPopulatorTest.java dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/VmInfoPopulatorTest.java dev/data-populator/src/test/resources/testconfig dev/pom.xml dev/storage-populator/command/pom.xml dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommand.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/Activator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/AgentInfoPopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/BasePopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/CollectionPopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/HostInfoPopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/LocaleResources.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/NetworkInfoPopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/ThreadPopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/VmInfoPopulator.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/ConfigItem.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfig.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/ConfigItemTypeAdapter.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/NotImplementedException.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapter.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapterFactory.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapter.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/ProcessedRecords.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/Relationship.java dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/SharedState.java dev/storage-populator/command/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.CategoryRegistration dev/storage-populator/command/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration dev/storage-populator/command/src/main/resources/com/redhat/thermostat/storage/populator/command/locale/strings.properties dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommandTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/ActivatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/AgentInfoPopulatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/BasePopulatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/HostInfoPopulatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/NetworkInfoPopulatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/ThreadPopulatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/VmInfoPopulatorTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfigTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/ConfigItemTypeAdapterTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapterTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapterTest.java dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/dependencies/RelationshipTest.java dev/storage-populator/command/src/test/resources/invalid-config.json dev/storage-populator/command/src/test/resources/testconfig dev/storage-populator/command/src/test/resources/valid-config.json dev/storage-populator/distribution/pom.xml dev/storage-populator/distribution/thermostat-plugin.xml dev/storage-populator/pom.xml distribution/assembly/all-plugin-assembly.xml distribution/config/storage-populator/population-config-example-simple-threads.json distribution/config/storage-populator/population-config-example-simple.json distribution/pom.xml
diffstat 87 files changed, 4587 insertions(+), 4150 deletions(-) [+]
line wrap: on
line diff
--- a/dev/data-populator/example-configs/population-config-example-simple-threads.json	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-{
-    "records": [
-       {
-         "name": "agent-config",
-         "number": 2,
-         "alive": 2
-       },
-       {
-         "name": "host-info",
-         "number": 1
-       },
-       {
-         "name": "vm-thread-harvesting",
-         "number": 5
-       },
-       {
-         "name": "vm-info",
-         "number": 5,
-         "alive": 5 
-       },
-       {
-         "name": "network-info",
-         "number": 20
-       }
-    ],
-    
-    "relationships": [
-      {
-        "from": "agent-config",
-        "to": "vm-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "host-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "network-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "vm-thread-harvesting",
-        "key": "agentId"
-      },
-      {
-        "from": "vm-info",
-        "to": "vm-thread-harvesting",
-        "key": "vmId"
-      }
-    ]
-}
--- a/dev/data-populator/example-configs/population-config-example-simple-vm-deadlock.json	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-{
-    "records": [
-       {
-         "name": "agent-config",
-         "number": 2,
-         "alive": 2
-       },
-       {
-         "name": "host-info",
-         "number": 1
-       },
-       {
-         "name": "vm-deadlock-data",
-         "number": 2
-       },
-       {
-         "name": "vm-info",
-         "number": 5,
-         "alive": 5 
-       },
-       {
-         "name": "network-info",
-         "number": 20
-       }
-    ],
-    
-    "relationships": [
-      {
-        "from": "agent-config",
-        "to": "vm-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "host-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "network-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "vm-deadlock-data",
-        "key": "agentId"
-      },
-      {
-        "from": "vm-info",
-        "to": "vm-deadlock-data",
-        "key": "vmId"
-      }
-    ]
-}
--- a/dev/data-populator/example-configs/population-config-example-simple.json	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-{
-    "records": [
-       {
-         "name": "agent-config",
-         "number": 100,
-         "alive": 20
-       },
-       {
-         "name": "host-info",
-         "number": 1
-       },
-       {
-         "name": "vm-info",
-         "number": 50,
-         "alive": 40
-       },
-       {
-         "name": "network-info",
-         "number": 50
-       }
-    ],
-    
-    "relationships": [
-      {
-        "from": "agent-config",
-        "to": "vm-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "host-info",
-        "key": "agentId"
-      },
-      {
-        "from": "agent-config",
-        "to": "network-info",
-        "key": "agentId"
-      }
-    ]
-}
--- a/dev/data-populator/pom.xml	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2016 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <groupId>com.redhat.thermostat</groupId>
-    <artifactId>thermostat-devel-modules</artifactId>
-    <version>1.99.10-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-data-populator</artifactId>
-
-  <packaging>jar</packaging>
-  <description>
-    This is a tool for Thermostat developers alowing them
-    to get a pre-populated DB. It may be useful for:
-     - reproducing bugs.
-     - do performance tests (on fixed DB contents).
-     - development: It can be an aid for writing client bits
-       before the agent backend is available.
-    Main entry-point is the populate script.
-    After a build do:
-    ./dev/data-populator/target/populate
-  </description>
-
-  <name>Thermostat Data Populator</name>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-annotations</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-      <version>${gson.version}</version>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-storage-mongodb</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-thread-collector</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-  </dependencies>
-  
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifest>
-              <addClasspath>true</addClasspath>
-              <mainClass>com.redhat.thermostat.dev.populator.Main</mainClass>
-            </manifest>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-resources-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>copy-scripts</id>
-            <phase>prepare-package</phase>
-            <goals>
-              <goal>copy-resources</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}</outputDirectory>
-              <resources>
-                <resource>
-                  <directory>scripts</directory>
-                  <filtering>true</filtering>
-                </resource>
-              </resources>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>chmod</id>
-            <phase>prepare-package</phase>
-            <configuration>
-              <target>
-                <chmod file="${project.build.directory}/populate" perm="755" />
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-  
-</project>
-
--- a/dev/data-populator/scripts/populate	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#!/bin/bash
-JAVA=@thermostat.jdk.home@/bin/java
-THERMOSTAT_HOME=@thermostat.home@
-LIBS=$THERMOSTAT_HOME/libs
-PLUGINS=$THERMOSTAT_HOME/plugins
-CP="$LIBS/thermostat-storage-mongodb-@project.version@.jar"
-CP="$CP:$LIBS/thermostat-storage-core-@project.version@.jar"
-CP="$CP:$LIBS/thermostat-shared-config-@project.version@.jar"
-CP="$CP:$LIBS/thermostat-common-core-@project.version@.jar"
-CP="$CP:$LIBS/thermostat-annotations-@project.version@.jar"
-CP="$CP:$LIBS/thermostat-launcher-@project.version@.jar"
-CP="$CP:$LIBS/mongo-java-driver-@mongo-driver.version@.jar"
-CP="$CP:$LIBS/gson-@gson.version@.jar"
-CP="$CP:$LIBS/commons-beanutils-@commons-beanutils.version@.jar"
-CP="$CP:$LIBS/commons-logging-@commons-logging.version@.jar"
-CP="$CP:$PLUGINS/thread/thermostat-thread-collector-@project.version@.jar"
-CP="$CP:@project.build.directory@/thermostat-data-populator-@project.version@.jar"
-$JAVA -cp $CP \
-  -DTHERMOSTAT_HOME=$THERMOSTAT_HOME \
-  -DUSER_THERMOSTAT_HOME=@project.build.directory@ \
-  com.redhat.thermostat.dev.populator.Main  \
-  $@
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/Arguments.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-class Arguments {
-    
-    private static final String OPTIONS_PREFIX = "--";
-    private static final String DB_URL_NAME = "dbUrl";
-    private static final String USERNAME_NAME = "username";
-    private static final String PASSWORD_NAME = "password";
-    private static final String CONFIG_FILE_NAME = "config";
-    
-    private final Map<String, String> args;
-    
-    private Arguments() {
-        args = new HashMap<>();
-    }
-    
-    public String getDbUrl() {
-        return args.get(DB_URL_NAME);
-    }
-    
-    public String getUsername() {
-        return args.get(USERNAME_NAME);
-    }
-    
-    public String getPassword() {
-        return args.get(PASSWORD_NAME);
-    }
-    
-    public String getConfigFile() {
-        return args.get(CONFIG_FILE_NAME);
-    }
-    
-    private void addArgument(String name, String value) {
-        args.put(name, value);
-    }
-    
-    private void validate() throws IllegalArgumentException {
-        if (args.size() != 4) {
-            throw new IllegalStateException();
-        }
-        if (args.get(DB_URL_NAME) == null ||
-                args.get(PASSWORD_NAME) == null ||
-                args.get(USERNAME_NAME) == null ||
-                args.get(CONFIG_FILE_NAME) == null) {
-            throw new IllegalStateException();
-        }
-    }
-    
-    static Arguments processArguments(String[] args) throws IllegalArgumentException {
-        if (args.length != 8) {
-            throw new IllegalArgumentException("missing required arguments");
-        }
-        Arguments myArgs = new Arguments();
-        for (int i = 0; i < args.length - 1; i += 2) {
-            String optionName = args[i];
-            String optionValue = args[i+1];
-            if (!optionName.startsWith(OPTIONS_PREFIX)) {
-                throw new IllegalArgumentException();
-            } else {
-                if (optionValue.startsWith(OPTIONS_PREFIX)) {
-                    throw new IllegalArgumentException();
-                }
-                myArgs.addArgument(optionName.substring(OPTIONS_PREFIX.length()), optionValue);
-            }
-        }
-        try {
-            myArgs.validate();
-        } catch (IllegalStateException e) {
-            throw new IllegalArgumentException("Missing required arguments");
-        }
-        return myArgs;
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/CollectionPopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-
-public interface CollectionPopulator {
-
-    SharedState addPojos(Storage storage, ConfigItem item, SharedState relState);
-    
-    String getHandledCollection();
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/ConnectionEstablisher.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator;
-
-import java.util.concurrent.CountDownLatch;
-
-import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
-import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl;
-import com.redhat.thermostat.storage.core.Connection;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
-import com.redhat.thermostat.storage.mongodb.MongoStorageProvider;
-
-class ConnectionEstablisher {
-
-    private final Arguments args;
-    
-    ConnectionEstablisher(Arguments args) {
-        this.args = args;
-    }
-    
-    Storage connectToStorage() {
-        MongoStorageProvider provider = new MongoStorageProvider();
-        StorageCredentials creds = getStorageCredentialsFromArgs(args);
-        provider.setConfig(args.getDbUrl(), creds, new SSLConfigurationImpl(new CommonPathsImpl()));
-        Storage storage = provider.createStorage();
-        Connection conn = storage.getConnection();
-        final CountDownLatch latch = new CountDownLatch(1);
-        conn.addListener(new Connection.ConnectionListener() {
-            
-            @Override
-            public void changed(ConnectionStatus newStatus) {
-                switch (newStatus) {
-                case CONNECTED: // fall-through
-                case FAILED_TO_CONNECT:
-                    latch.countDown();
-                    break;
-                default:
-                    // nothing
-                }
-            }
-        });
-        conn.connect();
-        try {
-            latch.await();
-        } catch (InterruptedException e) {
-            throw new RuntimeException("Storage connection interrupted");
-        }
-        return storage;
-    }
-
-    private StorageCredentials getStorageCredentialsFromArgs(final Arguments args) {
-        return new StorageCredentials() {
-            
-            @Override
-            public String getUsername() {
-                return args.getUsername();
-            }
-            
-            @Override
-            public char[] getPassword() {
-                return args.getPassword().toCharArray();
-            }
-        };
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/Main.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator;
-
-public class Main {
-
-    public static void main(String[] args) {
-        Arguments processedArgs = null;
-        try {
-            processedArgs = Arguments.processArguments(args);
-        } catch (IllegalArgumentException e) {
-            System.err.println("Error parsing arguments.");
-            e.printStackTrace(System.err);
-            printUsageAndExit();
-        }
-        StoragePopulator populator = new StoragePopulator(processedArgs);
-        populator.populate();
-        System.exit(0);
-    }
-    
-    private static void printUsageAndExit() {
-        System.err.println("Usage: populate --dbUrl <URL> --username <username> --password <password> --config path/to/population-config/file");
-        System.err.println();
-        System.err.println("Example (after thermostat-devsetup + 'thermostat storage --start'):");
-        System.err.println("populate --dbUrl mongodb://127.0.0.1:27518 --username mongodevuser --password mongodevpassword --config dev/data-populator/example-configs/population-config-example-simple.json");
-        System.exit(1);
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/StoragePopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ServiceLoader;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.config.PopulationConfig;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Connection;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
-
-class StoragePopulator {
-
-    private final Arguments args;
-    private final Map<String, CollectionPopulator> pojoPutters;
-    
-    StoragePopulator(Arguments args) {
-        this.args = args;
-        pojoPutters = getPopulatorsFromServiceLoader();
-    }
-    
-    private static Map<String, CollectionPopulator> getPopulatorsFromServiceLoader() {
-        ServiceLoader<CollectionPopulator> loader = ServiceLoader.load(CollectionPopulator.class);
-        Map<String, CollectionPopulator> populators = new HashMap<>();
-        for (CollectionPopulator putter: loader) {
-            populators.put(putter.getHandledCollection(), putter);
-        }
-        return populators;
-    }
-
-    public void populate() {
-        PopulationConfig config = getPopulationConfigFromArg();
-        Storage storage = connectToStorage();
-        addItemsToStorage(storage, config);
-        disconnectStorage(storage);
-        System.out.println("Data population finished successfully.");
-    }
-
-    private void disconnectStorage(Storage storage) {
-        Connection conn = storage.getConnection();
-        final CountDownLatch latch = new CountDownLatch(1);
-        conn.addListener(new Connection.ConnectionListener() {
-            
-            @Override
-            public void changed(ConnectionStatus newStatus) {
-                switch (newStatus) {
-                case DISCONNECTED:
-                    latch.countDown();
-                default:
-                    break;
-                }
-                
-            }
-        });
-        conn.disconnect();
-        try {
-            boolean expired = !latch.await(100, TimeUnit.MILLISECONDS);
-            if (expired) {
-                System.err.println("Timeout waiting for storage to disconnect.");
-            }
-        } catch (InterruptedException e) {
-            // ignore
-        }
-    }
-
-    private PopulationConfig getPopulationConfigFromArg() {
-        File configFile = new File(args.getConfigFile());
-        if (!configFile.exists()) {
-            throw new IllegalArgumentException("Config file '" + configFile.getAbsolutePath() + "' does not exist!");
-        }
-        String json;
-        PopulationConfig config;
-        try {
-            json = new String(Files.readAllBytes(configFile.toPath()));
-            config = PopulationConfig.parseFromJsonString(json);
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Failed to parse config file", e);
-        }
-        return config;
-    }
-
-    /**
-     * Add items to storage in topologically sorted order so as to have
-     * relevant depending state available.
-     * 
-     * @param storage The storage to add records for
-     * @param config The configuration describing the records to be added
-     */
-    private void addItemsToStorage(Storage storage, PopulationConfig config) {
-        SharedState state = new SharedState();
-        for (ConfigItem item: config.getConfigsTopologicallySorted()) {
-            state = addRecordsForConfig(storage, item, state);
-        }
-    }
-
-    private SharedState addRecordsForConfig(Storage storage, ConfigItem item, SharedState state) {
-        CollectionPopulator putter = pojoPutters.get(item.getName());
-        if (putter == null) {
-            System.err.println("No populator for collection '" + item.getName() + "' found. Skipping.");
-            return state; // return state unmodified
-        } else {
-            return putter.addPojos(storage, item, state);
-        }
-    }
-
-    private Storage connectToStorage() {
-        ConnectionEstablisher establisher = new ConnectionEstablisher(args);
-        return establisher.connectToStorage();
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/ConfigItem.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config;
-
-public class ConfigItem {
-
-    public static final String NAME = "name";
-    public static final String NUMBER = "number";
-    public static final String ALIVE = "alive";
-    
-    public static final int UNSET = -1;
-    private final int number;
-    private final int aliveItems;
-    private final String name;
-    
-    public ConfigItem(int number, int aliveItems, String name) {
-        this.number = number;
-        this.aliveItems = aliveItems;
-        this.name = name;
-    }
-
-    public int getNumber() {
-        return number;
-    }
-
-    public int getAliveItems() {
-        return aliveItems;
-    }
-
-    public String getName() {
-        return name;
-    }
-    
-    @Override
-    public String toString() {
-        return name + " (" + number + "/" + aliveItems + ")";
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/PopulationConfig.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.redhat.thermostat.dev.populator.config.typeadapter.ConfigItemTypeAdapter;
-import com.redhat.thermostat.dev.populator.config.typeadapter.PopulationConfigTypeAdapterFactory;
-import com.redhat.thermostat.dev.populator.config.typeadapter.RelationShipTypeAdapter;
-import com.redhat.thermostat.dev.populator.dependencies.Relationship;
-
-public class PopulationConfig {
-    
-    public static final String RECORDS = "records";
-    public static final String RELATIONSHIPS = "relationships";
-    private final Map<String, ConfigItem> configs;
-    private final List<ConfigItem> allConfigs;
-    private final Map<String, List<Relationship>> incomingRelationShips;
-    private final Map<String, List<Relationship>> outgoingRelationShips;
-    
-    private PopulationConfig() {
-        configs = new HashMap<>();
-        allConfigs = new ArrayList<>();
-        incomingRelationShips = new HashMap<>();
-        outgoingRelationShips = new HashMap<>();
-    }
-
-    public ConfigItem getConfig(String name) {
-        return configs.get(name);
-    }
-    
-    public List<ConfigItem> getConfigsTopologicallySorted() {
-        return topologicallySort(allConfigs);
-    }
-    
-    /**
-     * Sort config items topologically. That is, get them in an order so as
-     * to process collections with no incoming links to other collections.
-     * 
-     * It uses Kahn's algorithm to do so.
-     * 
-     * @param configs unsorted configs.
-     * @return A topologically sorted list.
-     */
-    private List<ConfigItem> topologicallySort(List<ConfigItem> configs) {
-        LinkedList<ConfigItem> sortedList = new LinkedList<>();
-        LinkedList<ConfigItem> queue = getConfigItemsWithNoIncomingEdge(configs);
-        while (!queue.isEmpty()) {
-            ConfigItem n = queue.remove(0);
-            sortedList.addLast(n);
-            List<Relationship> source = getOutgoingRelationShipsForConfig(n);
-            List<Relationship> outgoingRels = new LinkedList<>(source);
-            for (Relationship edge: outgoingRels) {
-                ConfigItem m = getConfig(edge.getTo());
-                removeEdge(edge, n, m);
-                if (hasNoIncomingEdge(m)) {
-                    queue.addLast(m);
-                }
-            }
-        }
-        if (hasRelationShips(configs)) {
-            throw new AssertionError("Relationships form at least one cycle! Excpected an acyclic directed graph.");
-        }
-        return sortedList;
-    }
-
-    private boolean hasRelationShips(List<ConfigItem> configs) {
-        for (ConfigItem i: configs) {
-            List<Relationship> incoming = getIncomingRelationShipsForConfig(i);
-            List<Relationship> outgoing = getOutgoingRelationShipsForConfig(i);
-            if (!incoming.isEmpty() ||
-                    !outgoing.isEmpty()) {
-                // We are going to bomb, print some debug info.
-                System.err.println("outgoings for " + i.getName() + " " + outgoing);
-                System.err.println("incomings for " + i.getName() + " " + incoming);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void removeEdge(Relationship toRemove, ConfigItem from, ConfigItem to) {
-        if (from == null || to == null) {
-            throw new InvalidConfigurationException("Found relationship [" +
-                                                    toRemove +
-                    "] but either incoming or outgoing records config is missing");
-        }
-        List<Relationship> incoming = getIncomingRelationShipsForConfig(to);
-        List<Relationship> outgoing = getOutgoingRelationShipsForConfig(from);
-        incoming.remove(toRemove);
-        outgoing.remove(toRemove);
-    }
-
-    private LinkedList<ConfigItem> getConfigItemsWithNoIncomingEdge(List<ConfigItem> allConfigs) {
-        LinkedList<ConfigItem> startNodes = new LinkedList<>();
-        for (ConfigItem item: allConfigs) {
-            if (hasNoIncomingEdge(item)) {
-                startNodes.add(item);
-            }
-        }
-        return startNodes;
-    }
-
-    private boolean hasNoIncomingEdge(ConfigItem item) {
-        List<Relationship> rels = getIncomingRelationShipsForConfig(item);
-        if (rels == null || rels.isEmpty()) {
-            return true;
-        }
-        return false;
-    }
-
-    private List<Relationship> getIncomingRelationShipsForConfig(ConfigItem item) {
-        List<Relationship> result = incomingRelationShips.get(item.getName());
-        if (result == null) {
-            return Collections.emptyList();
-        }
-        return result;
-    }
-    
-    private List<Relationship> getOutgoingRelationShipsForConfig(ConfigItem item) {
-        List<Relationship> result = outgoingRelationShips.get(item.getName());
-        if (result == null) {
-            return Collections.emptyList();
-        }
-        return result;
-    }
-    
-    private void addConfig(ConfigItem item) {
-        configs.put(item.getName(), item);
-        allConfigs.add(item);
-    }
-    
-    private void addIncomingRelationShipForConfig(ConfigItem item, Relationship relationship) {
-        addRelationShip(item, relationship, incomingRelationShips);
-    }
-    
-    private void addOutgoingRelationShipForConfig(ConfigItem item, Relationship relationship) {
-        addRelationShip(item, relationship, outgoingRelationShips);
-    }
-    
-    private void addRelationShip(ConfigItem item, Relationship relationship, Map<String, List<Relationship>> map) {
-        List<Relationship> existingRels = map.get(item.getName());
-        if (existingRels == null) {
-            existingRels = new LinkedList<>();
-            map.put(item.getName(), existingRels);
-        }
-        existingRels.add(relationship);
-    }
-    
-    public static PopulationConfig parseFromJsonString(String json) throws IOException {
-        Gson gson= new GsonBuilder()
-                        .registerTypeAdapter(ConfigItem.class, new ConfigItemTypeAdapter())
-                        .registerTypeAdapter(Relationship.class, new RelationShipTypeAdapter())
-                        .registerTypeAdapterFactory(new PopulationConfigTypeAdapterFactory())
-                        .create();
-        PopulationConfig pc = gson.fromJson(json, PopulationConfig.class);
-        return pc;
-    }
-    
-    public static PopulationConfig createFromLists(List<ConfigItem> items, List<Relationship> rels) {
-        PopulationConfig pc = new PopulationConfig();
-        for (ConfigItem item: items) {
-            pc.addConfig(item);
-            for (Relationship r: rels) {
-                // keep track of incoming relationships (incoming edge)
-                if (r.getTo().equals(item.getName())) {
-                    pc.addIncomingRelationShipForConfig(item, r);
-                }
-                // keep track of outgoing relationships (outgoing edge)
-                if (r.getFrom().equals(item.getName())) {
-                    pc.addOutgoingRelationShipForConfig(item, r);
-                }
-            }
-        }
-        return pc;
-    }
-    
-    @SuppressWarnings("serial")
-    static class InvalidConfigurationException extends RuntimeException {
-        
-        private InvalidConfigurationException(String msg) {
-            super(msg);
-        }
-
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/ConfigItemTypeAdapter.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
-import com.google.gson.stream.JsonWriter;
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-
-public class ConfigItemTypeAdapter extends TypeAdapter<ConfigItem> {
-
-    @Override
-    public ConfigItem read(JsonReader reader) throws IOException {
-        // handle null
-        if (reader.peek() == JsonToken.NULL) {
-            reader.nextNull();
-            return null;
-        }
-        
-        reader.beginObject();
-        ConfigItem item = parseConfigItem(reader);
-        reader.endObject();
-        
-        return item;
-    }
-
-    private ConfigItem parseConfigItem(JsonReader reader) throws IOException {
-        Map<String, Object> values = new HashMap<>();
-        while (reader.hasNext()) {
-            String name = reader.nextName();
-            switch(name) {
-            case ConfigItem.NAME:
-                values.put(ConfigItem.NAME, reader.nextString());
-                break;
-            case ConfigItem.ALIVE:
-                values.put(ConfigItem.ALIVE, reader.nextInt());
-                break;
-            case ConfigItem.NUMBER:
-                values.put(ConfigItem.NUMBER, reader.nextInt());
-                break;
-            default:
-                throw new IllegalStateException("Unknown config value: '" + name + "'");
-            }
-        }
-        String collName = (String)values.get(ConfigItem.NAME);
-        String collectionDetails = collName == null ? "" : "[" + collName + "] ";
-        Integer number = (Integer)values.get(ConfigItem.NUMBER);
-        Integer aliveItems = (Integer)values.get(ConfigItem.ALIVE);
-        int aliveItemsForSanityTest = getAliveCount(aliveItems);
-        if (number < 0 || aliveItemsForSanityTest < 0) {
-            throw new IllegalArgumentException(collectionDetails + "number of items and alive items must be positive");
-        }
-        if (number - aliveItemsForSanityTest < 0) {
-            throw new IllegalArgumentException(collectionDetails + "alive items > number of total items.");
-        }
-        return new ConfigItem(getValue(number), getValue(aliveItems), collName);
-    }
-
-    private int getAliveCount(Integer aliveItems) {
-        if (aliveItems != null) {
-            return aliveItems;
-        }
-        return 0; // return 0 for unset, just so that we make sanity checks happy
-    }
-
-    private int getValue(Integer value) {
-        return value == null ? ConfigItem.UNSET : value;
-    }
-
-    @Override
-    public void write(JsonWriter writer, ConfigItem item) throws IOException {
-        throw new NotImplementedException();
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/NotImplementedException.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-@SuppressWarnings("serial")
-class NotImplementedException extends RuntimeException {
-    // nothing
-}
\ No newline at end of file
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/PopulationConfigTypeAdapter.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.google.gson.Gson;
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
-import com.google.gson.stream.JsonWriter;
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.config.PopulationConfig;
-import com.redhat.thermostat.dev.populator.dependencies.Relationship;
-
-public class PopulationConfigTypeAdapter extends TypeAdapter<PopulationConfig> {
-    
-    private final Gson gson;
-    
-    public PopulationConfigTypeAdapter(Gson gson) {
-        this.gson = gson;
-    }
-
-    @Override
-    public void write(JsonWriter out, PopulationConfig config) throws IOException {
-        throw new NotImplementedException();
-    }
-
-    @Override
-    public PopulationConfig read(JsonReader in) throws IOException {
-        // handle null
-        if (in.peek() == JsonToken.NULL) {
-            in.nextNull();
-            return null;
-        }
-        in.beginObject();
-        PopulationConfig config = parsePopulationConfig(in);
-        in.endObject();
-        return config;
-    }
-
-    private PopulationConfig parsePopulationConfig(JsonReader in) throws IOException {
-        Map<String, Object> values = new HashMap<>();
-        while (in.hasNext()) {
-            String name = in.nextName();
-            switch(name) {
-            case PopulationConfig.RECORDS:
-                values.put(PopulationConfig.RECORDS, parseRecords(in));
-                break;
-            case PopulationConfig.RELATIONSHIPS:
-                values.put(PopulationConfig.RELATIONSHIPS, parseRelationships(in));
-                break;
-            default:
-                throw new IllegalStateException("Unknown population config value: '" + name + "'");
-            }
-        }
-        ConfigItem[] rawItems = (ConfigItem[])values.get(PopulationConfig.RECORDS);
-        Relationship[] rawRels = (Relationship[])values.get(PopulationConfig.RELATIONSHIPS);
-        List<Relationship> rels;
-        if (rawRels == null) {
-            rels = Collections.emptyList();
-        } else {
-            rels = Arrays.asList(rawRels);
-        }
-        return PopulationConfig.createFromLists(Arrays.asList(rawItems), rels);
-    }
-
-    private Relationship[] parseRelationships(JsonReader in) {
-        return gson.fromJson(in, Relationship[].class);
-    }
-
-    private ConfigItem[] parseRecords(JsonReader in) throws IOException {
-        return gson.fromJson(in, ConfigItem[].class);
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/PopulationConfigTypeAdapterFactory.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import com.google.gson.Gson;
-import com.google.gson.TypeAdapter;
-import com.google.gson.TypeAdapterFactory;
-import com.google.gson.reflect.TypeToken;
-import com.redhat.thermostat.dev.populator.config.PopulationConfig;
-
-public class PopulationConfigTypeAdapterFactory implements TypeAdapterFactory {
-
-    @Override
-    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
-        Class<?> rawType = type.getRawType();
-        if (rawType == PopulationConfig.class) {
-            @SuppressWarnings("unchecked")
-            TypeAdapter<T> ta = (TypeAdapter<T>)new PopulationConfigTypeAdapter(gson);
-            return ta;
-        }
-        return null;
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/config/typeadapter/RelationShipTypeAdapter.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
-import com.google.gson.stream.JsonWriter;
-import com.redhat.thermostat.dev.populator.dependencies.Relationship;
-
-public class RelationShipTypeAdapter extends TypeAdapter<Relationship> {
-
-    @Override
-    public Relationship read(JsonReader in) throws IOException {
-        // handle null
-        if (in.peek() == JsonToken.NULL) {
-            in.nextNull();
-            return null;
-        }
-        
-        in.beginObject();
-        Relationship rel = parseRelationShip(in);
-        in.endObject();
-        
-        return rel;
-    }
-
-    private Relationship parseRelationShip(JsonReader in) throws IOException {
-        Map<String, String> values = new HashMap<>();
-        while (in.hasNext()) {
-            String name = in.nextName();
-            switch(name) {
-            case Relationship.FROM:
-                values.put(Relationship.FROM, in.nextString());
-                break;
-            case Relationship.TO:
-                values.put(Relationship.TO, in.nextString());
-                break;
-            case Relationship.KEY:
-                values.put(Relationship.KEY, in.nextString());
-                break;
-            default:
-                throw new IllegalStateException("Unknown relationship value: '" + name + "'");
-            }
-        }
-        return new Relationship(values.get(Relationship.FROM), values.get(Relationship.TO), values.get(Relationship.KEY));
-    }
-
-    @Override
-    public void write(JsonWriter out, Relationship relationship) throws IOException {
-        throw new NotImplementedException();
-    }
-    
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/dependencies/ProcessedRecords.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.dependencies;
-
-import java.util.List;
-
-/**
- *
- * @param <T> The underlying type of the key
- */
-public class ProcessedRecords<T> {
-
-    private final List<T> allRecords;
-    
-    public ProcessedRecords(List<T> allRecords) {
-        this.allRecords = allRecords;
-    }
-    
-    public List<T> getAll() {
-        return allRecords;
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/dependencies/Relationship.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.dependencies;
-
-import java.util.Objects;
-
-public class Relationship {
-
-    public static final String TO = "to";
-    public static final String FROM = "from";
-    public static final String KEY = "key";
-    private final String from;
-    private final String to;
-    private final String key;
-    
-    public Relationship(String from, String to, String key) {
-        this.from = from;
-        this.to = to;
-        this.key = key;
-    }
-
-    public String getFrom() {
-        return from;
-    }
-
-    public String getTo() {
-        return to;
-    }
-
-    public String getKey() {
-        return key;
-    }
-    
-    @Override
-    public boolean equals(Object o) {
-        if (o == null || o.getClass() != Relationship.class) {
-            return false;
-        }
-        Relationship other = (Relationship)o;
-        return Objects.equals(to, other.to) &&
-                Objects.equals(from, other.from) &&
-                Objects.equals(key, other.key);
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hash(to, from, key);
-    }
-    
-    @Override
-    public String toString() {
-        return from + " -> " + to + "(" + key + ")";
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/dependencies/SharedState.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.dependencies;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class SharedState {
-    
-    private final Map<Object, ProcessedRecords<?>> processedRecs;
-    private final Map<String, Object> props;
-    
-    public SharedState() {
-        processedRecs = new HashMap<>();
-        props = new HashMap<>();
-    }
-
-    public <T> ProcessedRecords<T> getProcessedRecordsFor(T key) {
-        @SuppressWarnings("unchecked")
-        ProcessedRecords<T> item = (ProcessedRecords<T>)processedRecs.get(key);
-        return item;
-    }
-    
-    public <T> void addProcessedRecords(T key, ProcessedRecords<T> recs) {
-        processedRecs.put(key, recs);
-    }
-    
-    public void addProperty(String key, Object value) {
-        props.put(key, value);
-    }
-    
-    public Object getProperty(String key) {
-        return props.get(key);
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/AgentInfoPopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class AgentInfoPopulator extends BasePopulator {
-    
-    private final AgentInfoDAO dao;
-    
-    public AgentInfoPopulator() {
-        this(null);
-    }
-    
-    // for testing
-    AgentInfoPopulator(AgentInfoDAO dao) {
-        this.dao = dao;
-    }
-
-    @Override
-    public SharedState addPojos(Storage storage, ConfigItem item, SharedState state) {
-        // Default to all alive, if unset
-        int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems();
-        List<String> processedRecords = new ArrayList<>(); 
-        AgentInfoDAO agentInfoDao = getDao(storage);
-        long currentTime = System.currentTimeMillis();
-        long countBefore = agentInfoDao.getCount();
-        System.out.println("Populating "+ item.getNumber() + " " + item.getName() + " records");
-        for (int i = 0; i < item.getNumber(); i++) {
-            AgentInformation agentInfo = new AgentInformation();
-            String agentId = UUID.randomUUID().toString();
-            processedRecords.add(agentId);
-            agentInfo.setAgentId(agentId);
-            agentInfo.setAlive(getAliveValue(aliveItems, i));
-            agentInfo.setConfigListenAddress(String.format("127.0.0.1:%d", i));
-            agentInfo.setStartTime(currentTime);
-            agentInfoDao.addAgentInformation(agentInfo);
-            reportProgress(item, i);
-        }
-        doWaitUntilCount(agentInfoDao, countBefore + item.getNumber());
-        state.addProcessedRecords("agentId", new ProcessedRecords<>(processedRecords));
-        // FIXME: Why does HostInfoDAOImpl need AgentInfoDAO? See HostInfoPopulator
-        state.addProperty("agent-info-dao", agentInfoDao);
-        return state;
-    }
-
-    private boolean getAliveValue(int aliveItems, int i) {
-        if (i < aliveItems) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    private AgentInfoDAO getDao(Storage storage) {
-        if (dao == null) {
-            return new AgentInfoDAOImpl(storage);
-        } else {
-            return dao;
-        }
-    }
-
-    @Override
-    public String getHandledCollection() {
-        return AgentInfoDAO.CATEGORY.getName();
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/BasePopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import com.redhat.thermostat.dev.populator.CollectionPopulator;
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.storage.core.Countable;
-
-public abstract class BasePopulator implements CollectionPopulator {
-
-    protected void doWaitUntilCount(Countable countable, long expectedCount) {
-        System.out.print("Waiting for storage items to arrive at backend...");
-        long currCount = countable.getCount();
-        while (currCount != expectedCount) {
-            try {
-                Thread.sleep(200);
-                System.out.print("."); // report some progress
-            } catch (InterruptedException e) {
-                // ignore
-            }
-            currCount = countable.getCount();
-        }
-        System.out.println(" Done.");
-    }
-    
-    protected void reportProgress(ConfigItem item, int currCount) {
-        if (currCount > 0 && currCount % 10 == 0) {
-            System.out.println("Submitted " + currCount + " " + item.getName() + " records to storage.");
-        }
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/HostInfoPopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import java.util.List;
-import java.util.Objects;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.HostInfoDAOImpl;
-import com.redhat.thermostat.storage.model.HostInfo;
-
-public class HostInfoPopulator extends BasePopulator {
-    
-    private static final String[] HOSTS_FORMAT = new String[] {
-            "vm-host-%06d", "prometheus-%06d", "saturn-%06d"
-    };
-    private static final String DOMAIN_FORMAT = "domain-%06d";
-    private static final String HOSTNAME_SUFFIX = "example.com";
-    private static final long MB = 1024 * 1024;
-    private final HostInfoDAO dao;
-    
-    public HostInfoPopulator() {
-        this(null);
-    }
-
-    HostInfoPopulator(HostInfoDAO dao) {
-        this.dao = dao;
-    }
-
-    @Override
-    public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) {
-        // FIXME: We need the same instance of the AgentInfoDAO due to the register-category quirk.
-        AgentInfoDAO agentInfoDAO = Objects.requireNonNull((AgentInfoDAO)relState.getProperty("agent-info-dao"));
-        HostInfoDAO hostDAO = getDao(storage, agentInfoDAO);
-        List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll();
-        int totalItems = agentIds.size();
-        int currCount = 0;
-        long countBefore = hostDAO.getCount();
-        System.out.println("Populating "+ totalItems  + " " + item.getName() + " records");
-        // There is a 1-to-1 correspondance between host-info and agents
-        for (int i = agentIds.size() - 1; i >= 0; i--) {
-            String agentId = agentIds.get(i);
-            HostInfo info = new HostInfo();
-            info.setAgentId(agentId);
-            info.setCpuCount(getRandomInt(50 + i));
-            info.setCpuModel("x86_64, data populator");
-            info.setHostname(getRandomHostName(i));
-            info.setOsKernel("4.2.3 data populator");
-            info.setOsName("Linux Random Flavor");
-            int memory = getRandomInt(500 + i);
-            info.setTotalMemory(memory * MB);
-            hostDAO.putHostInfo(info);
-            reportProgress(item, currCount);
-            currCount++;
-        }
-        doWaitUntilCount(hostDAO, countBefore + totalItems);
-        return relState;
-    }
-
-    private String getRandomHostName(int i) {
-        int index = getRandomInt(HOSTS_FORMAT.length);
-        String hostFormat = HOSTS_FORMAT[index] + "." + DOMAIN_FORMAT + "." + HOSTNAME_SUFFIX;
-        return String.format(hostFormat, i, i);
-    }
-
-    private int getRandomInt(int i) {
-        return (int)(Math.random() * i);
-    }
-
-    @Override
-    public String getHandledCollection() {
-        return HostInfoDAO.hostInfoCategory.getName();
-    }
-    
-    // hook for testing
-    private HostInfoDAO getDao(Storage storage, AgentInfoDAO agentInfoDAO) {
-        if (dao == null) {
-            return new HostInfoDAOImpl(storage, agentInfoDAO);
-        } else {
-            return dao;
-        }
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/NetworkInfoPopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import java.util.List;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.CategoryAdapter;
-import com.redhat.thermostat.storage.core.Countable;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl;
-import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
-
-public class NetworkInfoPopulator extends BasePopulator {
-    
-    static final String[] IPV4_FORMATS = new String[] {
-            "192.168.0.%d", "10.33.4.%d", "89.15.93.%d" 
-    };
-    static final String[] IPV6_FORMATS = new String[] {
-            "e8:b1:fc:d2:e3:%s%%%s", "fe80::56ee:75ff:fe35:%s%%%s",
-            "0:0:0:0:0:0:0:%s%%%s"
-    };
-    private final String[] IFACE_NAMES = new String[] {
-            "lo", "enp0s25", "tun0", "virbr0", "wlp4s0"
-    };
-    private static int IPv6Mod = Integer.parseInt("ffff", 16);
-    private static int IPv4Mod = 255;
-    
-    private final NetworkInterfaceDAOCountable dao;
-    
-    public NetworkInfoPopulator() {
-        this(null);
-    }
-    
-    NetworkInfoPopulator(NetworkInterfaceDAOCountable dao) {
-        this.dao = dao;
-    }
-
-    @Override
-    public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) {
-        ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId");
-        NetworkInterfaceDAOCountable dao = getDao(storage);
-        List<String> allAgents = procAgents.getAll();
-        long countBefore = dao.getCount();
-        int totalItems = item.getNumber() * allAgents.size();
-        // populate network info records per agentID
-        System.out.println("Populating "+ totalItems  + " " + item.getName() + " records");
-        int currVal = 0;
-        for (String agentId: allAgents) {
-            for (int i = 0; i < item.getNumber(); i++) {
-                NetworkInterfaceInfo info = new NetworkInterfaceInfo();
-                info.setAgentId(agentId);
-                String name = getRandomInterfaceName(i);
-                info.setInterfaceName(name);
-                info.setIp6Addr(getRandomIpv6Address(i, name));
-                info.setIp4Addr(getRandomIpv4Addrees(i));
-                dao.putNetworkInterfaceInfo(info);
-                reportProgress(item, currVal);
-                currVal++;
-            }
-        }
-        doWaitUntilCount(dao, countBefore + totalItems);
-        return relState;
-    }
-
-    private String getRandomIpv4Addrees(int i) {
-        int idx = getRandomInt(IPV4_FORMATS.length);
-        return String.format(IPV4_FORMATS[idx], getIpv4Octet(i));
-    }
-
-    private int getRandomInt(int upperBound) {
-        return (int)(Math.random() * upperBound);
-    }
-
-    private String getRandomIpv6Address(int i, String name) {
-        int idx = getRandomInt(IPV6_FORMATS.length);
-        return String.format(IPV6_FORMATS[idx], getIpv6Hextet(i), name);
-    }
-    
-    // package-private for testing
-    String getIpv6Hextet(int i) {
-        int remainder = i % IPv6Mod;
-        if (remainder == 0) {
-            // 0 isn't really an IP, make it 1 instead.
-            remainder = 1;
-        }
-        return Integer.toHexString(remainder);
-    }
-    
-    // package-private for testing
-    int getIpv4Octet(int i) {
-        int remainder = i % IPv4Mod;
-        if (remainder == 0) {
-            // 0 is network address, switch to IP
-            remainder = 1;
-        }
-        return remainder;
-    }
-
-    private String getRandomInterfaceName(int i) {
-        int idx = getRandomInt(IFACE_NAMES.length);
-        return IFACE_NAMES[idx] + i;
-    }
-
-    private NetworkInterfaceDAOCountable getDao(Storage storage) {
-        if (this.dao == null) {
-            return new NetworkInterfaceDAOCountable(storage);
-        }
-        return dao;
-    }
-
-    @Override
-    public String getHandledCollection() {
-        return NetworkInterfaceInfoDAO.networkInfoCategory.getName();
-    }
-    
-    static class NetworkInterfaceDAOCountable extends NetworkInterfaceInfoDAOImpl implements Countable {
-
-        private final Category<AggregateCount> aggregateCategory;
-        private final Storage storage;
-        
-        NetworkInterfaceDAOCountable(Storage storage) {
-            super(storage);
-            CategoryAdapter<NetworkInterfaceInfo, AggregateCount> adapter = new CategoryAdapter<>(networkInfoCategory);
-            aggregateCategory = adapter.getAdapted(AggregateCount.class);
-            storage.registerCategory(aggregateCategory);
-            this.storage = storage;
-        }
-
-        @Override
-        public long getCount() {
-            String descriptor = "QUERY-COUNT " + networkInfoCategory.getName();
-            try {
-                PreparedStatement<AggregateCount> stmt = storage.prepareStatement(new StatementDescriptor<>(aggregateCategory, descriptor));
-                Cursor<AggregateCount> cursor = stmt.executeQuery();
-                AggregateCount count = cursor.next();
-                return count.getCount();
-            } catch (DescriptorParsingException | StatementExecutionException e) {
-                throw new RuntimeException(e);
-            }
-        }
-        
-    }
-
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/ThreadPopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-import com.redhat.thermostat.common.Pair;
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.CategoryAdapter;
-import com.redhat.thermostat.storage.core.Countable;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.thread.dao.ThreadDao;
-import com.redhat.thermostat.thread.dao.internal.ThreadDaoImpl;
-import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
-import com.redhat.thermostat.thread.model.ThreadSession;
-import com.redhat.thermostat.thread.model.ThreadState;
-import com.redhat.thermostat.thread.model.ThreadSummary;
-import com.redhat.thermostat.thread.model.VmDeadLockData;
-
-public class ThreadPopulator extends BasePopulator {
-
-    /**
-     * Package-private and static for testing.
-     */
-    static final int NUM_SAMPLES = 10;
-
-    public final String SESSION = "session";
-    private final int NUM_THREADS = 3;
-    private final long SEED = 5;
-    Random generator = new Random(SEED);
-    private static final String[] THREAD_NAMES = new String[] {
-            "Spencer", "Sheldon", "Alice", "Bob", "Julie", "Phoebe", "Alpha", "Beta", "Gamma",
-            "Theta", "Zeta",
-    };
-    static final String DEADLOCK_DESC_FORMAT = "" +
-            "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"%s\" Id=%d\n" +
-            "\tat sun.misc.Unsafe.park(Native Method)\n" +
-            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
-            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
-            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
-            "\t...\n\n" +
-            "\tNumber of locked synchronizers = 1\n" +
-            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" +
-            "\n\n" +
-            "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"%s\" Id=%d\n" +
-            "\tat sun.misc.Unsafe.park(Native Method)\n" +
-            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + 
-            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + 
-            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
-            "\t...\n\n" + 
-            "\tNumber of locked synchronizers = 1\n" +
-            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
-            "\n\n" +
-            "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"%s\" Id=%d\n" +
-            "\tat sun.misc.Unsafe.park(Native Method)\n" +
-            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" +
-            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + 
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + 
-            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
-            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + 
-            "\t...\n\n" +
-            "\tNumber of locked synchronizers = 1\n" +
-            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n";
-            
-    
-    private ThreadDaoCountable dao;
-
-    public ThreadPopulator() {
-        this(null);
-    }
-
-    ThreadPopulator(ThreadDaoCountable dao) {
-        this.dao = dao;
-    }
-
-    // Testing hook
-    private void createDao(Storage storage) {
-        if (dao == null) {
-            dao = new ThreadDaoCountable(storage);
-        }
-    }
-
-    @Override
-    public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) {
-        createDao(storage);
-        // creates records per agent *and* vm
-        List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll();
-        List<String> vmIds = relState.getProcessedRecordsFor("vmId").getAll();
-        int perVmNumber = item.getNumber();
-        int totalCount = perVmNumber * agentIds.size() * vmIds.size();
-        int currCount = 0;
-        long countBefore = dao.getCount();
-        System.out.println("Populating "+ totalCount  + " " + item.getName() + " records");
-        long currTime = System.currentTimeMillis();
-        for (String agentId: agentIds) {
-            for (String vmId: vmIds) {
-                for (int i = 0; i < perVmNumber; i++) {
-                    ThreadSummary summary = new ThreadSummary();
-                    summary.setAgentId(agentId);
-                    summary.setVmId(vmId);
-                    int liveThreads = generator.nextInt(NUM_THREADS);
-                    summary.setCurrentLiveThreads(liveThreads);
-                    int daemonThreads = NUM_THREADS - liveThreads;
-                    summary.setCurrentDaemonThreads(daemonThreads);
-                    long timeStamp = currTime + i * 1000;
-                    summary.setTimeStamp(timeStamp);
-                    dao.saveSummary(summary);
-
-                    ThreadSession session = new ThreadSession();
-                    session.setSession(SESSION);
-                    session.setTimeStamp(timeStamp);
-                    session.setAgentId(agentId);
-                    session.setVmId(vmId);
-                    dao.saveSession(session);
-
-                    final Thread.State[] states = Thread.State.values();
-                    String state = states[generator.nextInt(states.length)].toString();
-                    String name = THREAD_NAMES[generator.nextInt(THREAD_NAMES.length)];
-
-                    for(int j = 0; j < NUM_SAMPLES; j++) {
-                        ThreadState threadState = new ThreadState();
-                        threadState.setTimeStamp(currTime + j * 1000);
-                        threadState.setVmId(vmId);
-                        threadState.setAgentId(agentId);
-                        threadState.setState(state);
-                        threadState.setId(i);
-                        threadState.setName(name);
-                        threadState.setSession(SESSION);
-                        dao.addThreadState(threadState);
-                    }
-
-                    ThreadHarvestingStatus status = new ThreadHarvestingStatus(agentId);
-                    status.setVmId(vmId);
-                    status.setTimeStamp(timeStamp);
-                    status.setHarvesting(generator.nextBoolean());
-                    dao.saveHarvestingStatus(status);
-
-                    VmDeadLockData data = new VmDeadLockData();
-                    data.setAgentId(agentId);
-                    data.setVmId(vmId);
-                    data.setTimeStamp(currTime + i * 10);
-                    data.setDeadLockDescription(getDeadlockedDescription(currCount));
-                    dao.saveDeadLockStatus(data);
-                    currCount++;
-                    reportProgress(item, currCount);
-                }
-            }
-        }
-        doWaitUntilCount(dao, countBefore + totalCount);
-        return relState;
-    }
-
-    private String getDeadlockedDescription(int currCount) {
-        return String.format(DEADLOCK_DESC_FORMAT, getFormatStringArgs(currCount));
-    }
-
-    Object[] getFormatStringArgs(int currCount) {
-        List<Pair<String, Integer>> nameIdMapping = new ArrayList<>();
-        int[] randomIds = getIdValues(currCount, NUM_THREADS);
-        int randomEntry = getRandomInt(THREAD_NAMES.length);
-        for (int i = 0, idx; i < NUM_THREADS; i++) {
-            idx = (randomEntry + i) % THREAD_NAMES.length;
-            String name = THREAD_NAMES[idx];
-            int tid = randomIds[i];
-            nameIdMapping.add(new Pair<>(name, tid));
-        }
-        Object[] formatArgs = new Object[NUM_THREADS * 2 * 2];
-        formatArgs[0] = nameIdMapping.get(0).getFirst();
-        formatArgs[1] = nameIdMapping.get(0).getSecond();
-        for (int i = 2, j = 1; i < formatArgs.length - 2; i+= 4, j++) {
-            formatArgs[i] = nameIdMapping.get(j).getFirst();
-            formatArgs[i + 1] = nameIdMapping.get(j).getSecond();
-            formatArgs[i + 2] = nameIdMapping.get(j).getFirst();
-            formatArgs[i + 3] = nameIdMapping.get(j).getSecond();
-        }
-        formatArgs[formatArgs.length - 2] = nameIdMapping.get(0).getFirst();
-        formatArgs[formatArgs.length - 1] = nameIdMapping.get(0).getSecond();
-        return formatArgs;
-    }
-
-    private int getRandomInt(int len) {
-        return (int)(Math.random() * len);
-    }
-
-    private int[] getIdValues(int currCount, int length) {
-        int[] values = new int[length];
-        for (int i = 0; i < values.length; i++) {
-            values[i] = currCount + i;
-        }
-        return values;
-    }
-
-    @Override
-    public String getHandledCollection() {
-        return ThreadDao.THREAD_HARVESTING_STATUS.getName();
-    }
-
-    static class ThreadDaoCountable extends ThreadDaoImpl implements Countable {
-
-        private final Category<AggregateCount> aggregateCategory;
-        private final Storage storage;
-
-        public ThreadDaoCountable(Storage storage) {
-            super(storage);
-            CategoryAdapter<VmDeadLockData, AggregateCount> adapter = new CategoryAdapter<>(DEADLOCK_INFO);
-            aggregateCategory = adapter.getAdapted(AggregateCount.class);
-            storage.registerCategory(aggregateCategory);
-            this.storage = storage;
-        }
-
-        @Override
-        public long getCount() {
-            String descriptor = "QUERY-COUNT " + DEADLOCK_INFO.getName();
-            try {
-                PreparedStatement<AggregateCount> stmt = storage.prepareStatement(new StatementDescriptor<>(aggregateCategory, descriptor));
-                Cursor<AggregateCount> cursor = stmt.executeQuery();
-                AggregateCount count = cursor.next();
-                return count.getCount();
-            } catch (DescriptorParsingException | StatementExecutionException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-    }
-}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/VmInfoPopulator.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmInfoPopulator extends BasePopulator {
-
-    private final VmInfoDAO dao;
-    
-    public VmInfoPopulator() {
-        this(null);
-    }
-    
-    VmInfoPopulator(VmInfoDAO dao) {
-        this.dao = dao;
-    }
-
-    @Override
-    public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) {
-        // Default to all alive, if unset
-        int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems();
-        ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId");
-        List<String> vmIds = new ArrayList<>();
-        VmInfoDAO dao = getDao(storage);
-        List<String> allAgents = procAgents.getAll();
-        long countBefore = dao.getCount();
-        int totalItems = item.getNumber() * allAgents.size();
-        // populate VM records per agentID
-        System.out.println("Populating "+ totalItems  + " " + item.getName() + " records");
-        int currVal = 0;
-        for (String agentId: allAgents) {
-            for (int i = 0; i < item.getNumber(); i++) {
-                VmInfo info = new VmInfo();
-                info.setAgentId(agentId);
-                info.setJavaCommandLine("java DataPopulatorProducedVM --vm " + i  + " --version");
-                info.setJavaHome("/opt/foo/bar/java-1.8.0-openjdk/jre");
-                info.setJavaVersion("1.8.0");
-                info.setMainClass("com.redhat.thermostat.TestDataPopulator");
-                info.setLoadedNativeLibraries(new String[] { "glibc.so", "something.so" });
-                info.setProperties(getFakeJavaProperties(i, agentId));
-                StartStopTimeStamp ts = getFakeStartStopTimeStamp(i, aliveItems);
-                info.setStartTimeStamp(ts.startTS);
-                info.setStopTimeStamp(ts.stopTS);
-                info.setUsername("vm-user-" + i);
-                info.setUid(i);
-                info.setVmArguments("-XX:+UseG1Gc");
-                String vmId = UUID.randomUUID().toString();
-                info.setVmId(vmId);
-                vmIds.add(vmId);
-                info.setVmInfo("OpenJDK 8");
-                info.setVmPid(34 + i);
-                info.setVmVersion("hs 25");
-                info.setVmName("Hotspot");
-                dao.putVmInfo(info);
-                reportProgress(item, currVal);
-                currVal++;
-            }
-        }
-        doWaitUntilCount(dao, countBefore + totalItems);
-        relState.addProcessedRecords("vmId", new ProcessedRecords<>(vmIds));
-        return relState;
-    }
-    
-    private StartStopTimeStamp getFakeStartStopTimeStamp(int num, int aliveItems) {
-        long currTime = System.currentTimeMillis();
-        if (num < aliveItems) {
-            // create alive timestamp pair
-            long startTs = Long.MAX_VALUE;
-            long stopTs = currTime;
-            return new StartStopTimeStamp(startTs, stopTs);
-        }
-        // create dead timestamp pair
-        return new StartStopTimeStamp(currTime - (1000 + num), currTime - (500 + num));
-    }
-
-    private Map<String, String> getFakeJavaProperties(int i, String agentId) {
-        Map<String, String> props = new HashMap<String, String>();
-        props.put("foo", "bar");
-        props.put("vm#", Integer.toString(i));
-        props.put("agentId", agentId);
-        return props;
-    }
-
-    // hook for testing
-    private VmInfoDAO getDao(Storage storage) {
-        if (dao == null) {
-            return new VmInfoDAOImpl(storage);
-        } else {
-            return dao;
-        }
-    }
-
-    @Override
-    public String getHandledCollection() {
-        return VmInfoDAO.vmInfoCategory.getName();
-    }
-    
-    private static class StartStopTimeStamp {
-        private final long startTS;
-        private final long stopTS;
-        
-        private StartStopTimeStamp(long start, long stop) {
-            this.startTS = start;
-            this.stopTS = stop;
-        }
-    }
-}
--- a/dev/data-populator/src/main/resources/META-INF/services/com.redhat.thermostat.dev.populator.CollectionPopulator	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-com.redhat.thermostat.dev.populator.internal.ThreadPopulator
-com.redhat.thermostat.dev.populator.internal.AgentInfoPopulator
-com.redhat.thermostat.dev.populator.internal.VmInfoPopulator
-com.redhat.thermostat.dev.populator.internal.HostInfoPopulator
-com.redhat.thermostat.dev.populator.internal.NetworkInfoPopulator
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/ArgumentsTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-public class ArgumentsTest {
-
-    @Test
-    public void canParseCorrectArgs() {
-        String[] args = new String[] {
-                "--username", "foo-user", "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--password", "foo-password",
-                "--config", "path/to/config"
-        };
-        Arguments parsedArgs = Arguments.processArguments(args);
-        assertValues(parsedArgs);
-        // different order
-        args = new String[] {
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--username", "foo-user", 
-                "--password", "foo-password",
-                "--config", "path/to/config"
-        };
-        parsedArgs = Arguments.processArguments(args);
-        assertValues(parsedArgs);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void failToParseUsernameMissing() {
-        String[] args = new String[] {
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--password", "foo-password",
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--config", "path/to/config"
-        };
-        Arguments.processArguments(args);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void failToParsePasswordMissing() {
-        String[] args = new String[] {
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--username", "foo-user",
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--config", "path/to/config"
-        };
-        Arguments.processArguments(args);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void failToParseDbUrlMissing() {
-        String[] args = new String[] {
-                "--username", "foo-user",
-                "--username", "foo-user",
-                "--password", "foo-password",
-                "--config", "path/to/config"
-        };
-        Arguments.processArguments(args);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void failToParseIllegalOptionValue() {
-        String[] args = new String[] {
-                "--username", "--foo-user", // -- in foo-user is wrong
-                "--username", "foo-user",
-                "--password", "foo-password",
-                "--config", "path/to/config"
-        };
-        Arguments.processArguments(args);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void failToParseIllegalOption() {
-        String[] args = new String[] {
-                "--username", "--foo-user",
-                "username", "foo-user", // epxected --username not username
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--password", "foo-password",
-                "--config", "path/to/config"
-        };
-        Arguments.processArguments(args);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void failToParseIllegalLength() {
-        String[] args = new String[] {
-                "--username", "--foo-user",
-                "--username", "foo-user",
-                "--dbUrl", "mongodb://127.0.0.1:27518",
-                "--password", "foo-password",
-                "--config", "path/to/config"
-        };
-        Arguments.processArguments(args);
-    }
-    
-    private void assertValues(Arguments parsedArgs) {
-        assertEquals("mongodb://127.0.0.1:27518", parsedArgs.getDbUrl());
-        assertEquals("foo-user", parsedArgs.getUsername());
-        assertEquals("foo-password", parsedArgs.getPassword());
-        assertEquals("path/to/config", parsedArgs.getConfigFile());
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/PopulationConfigTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.dev.populator.dependencies.Relationship;
-
-public class PopulationConfigTest {
-    
-    private static final String NETWORK_INFO_NAME = "network-info";
-    private static final String AGENT_CONFIG_NAME = "agent-config";
-    private static final String HOST_INFO_NAME = "host-info";
-    private static final String VM_INFO_NAME = "vm-info";
-    private static final String VM_GC_STAT_NAME = "vm-gc-stats";
-    private static final String AGENT_KEY = "foo-agent-key";
-    private static final String VM_KEY = "bar-vm-key";
-
-    @Test
-    public void canParseFromFile() throws IOException {
-        String json = new String(Files.readAllBytes(new File(getClass().getResource("/testconfig").getFile()).toPath()));
-        PopulationConfig config = PopulationConfig.parseFromJsonString(json);
-        ConfigItem item = config.getConfig("agent-config");
-        assertNotNull(item);
-        assertEquals(100, item.getNumber());
-        assertEquals(20, item.getAliveItems());
-        List<ConfigItem> items = config.getConfigsTopologicallySorted();
-        assertEquals(7, items.size());
-        item = config.getConfig("vm-info");
-        assertEquals(50, item.getNumber());
-        assertEquals(40, item.getAliveItems());
-        item = config.getConfig("vm-gc-stats");
-        assertNotNull(item);
-    }
-    
-    /**
-     * Tests topological sorting of a simple DAG
-     * 
-     * <pre>
-     * agent-config -> network-info
-     *    |----------> host-info
-     *    |--> vm-info
-     *    |      `--> vm-gc-stat
-     *    `------------^
-     * </pre>
-     * 
-     * @throws IOException
-     */
-    @Test
-    public void testTopogicalSort() throws IOException {
-        List<ConfigItem> records = buildGoodRecords();
-        List<Relationship> rels = buildGoodRels();
-        PopulationConfig pc = PopulationConfig.createFromLists(records, rels);
-        List<ConfigItem> topSortedList = pc.getConfigsTopologicallySorted();
-        assertAgentConfigBeforeNetworkInfo(topSortedList);
-        assertAgentConfigBeforeHostInfo(topSortedList);
-        assertAgentConfigBeforeVmInfo(topSortedList);
-        assertVmInfoBeforeVmGcStat(topSortedList);
-        assertAgentConfigBeforeVmGcStat(topSortedList);
-    }
-    
-    private void assertAgentConfigBeforeVmGcStat(List<ConfigItem> topSortedList) {
-        assertTrue(isABeforeB(AGENT_CONFIG_NAME, VM_GC_STAT_NAME, topSortedList));
-    }
-
-    private void assertVmInfoBeforeVmGcStat(List<ConfigItem> topSortedList) {
-        assertTrue(isABeforeB(VM_INFO_NAME, VM_GC_STAT_NAME, topSortedList));
-    }
-
-    private void assertAgentConfigBeforeVmInfo(List<ConfigItem> topSortedList) {
-        assertTrue(isABeforeB(AGENT_CONFIG_NAME, VM_INFO_NAME, topSortedList));
-    }
-
-    private void assertAgentConfigBeforeHostInfo(List<ConfigItem> topSortedList) {
-        assertTrue(isABeforeB(AGENT_CONFIG_NAME, HOST_INFO_NAME, topSortedList));
-    }
-
-    private void assertAgentConfigBeforeNetworkInfo(List<ConfigItem> topSortedList) {
-        assertTrue(isABeforeB(AGENT_CONFIG_NAME, NETWORK_INFO_NAME, topSortedList));
-    }
-    
-    private boolean isABeforeB(String a, String b, List<ConfigItem> list) {
-        int idxA = -1;
-        int idxB = -1;
-        for (int i = 0; i < list.size(); i++) {
-            ConfigItem item = list.get(i);
-            if (item.getName().equals(a)) {
-                if (idxA >= 0) {
-                    throw new AssertionError("Illegal state. Re-assigning idxA!");
-                }
-                idxA = i;
-            }
-            if (item.getName().equals(b)) {
-                if (idxB >= 0) {
-                    throw new AssertionError("Illegal state. Re-assigning idxB!");
-                }
-                idxB = i;
-            }
-        }
-        return idxA < idxB;
-    }
-
-    private List<Relationship> buildGoodRels() {
-        List<Relationship> relationships = new LinkedList<>();
-        Relationship agentConfigToNetworkInfo = new Relationship(AGENT_CONFIG_NAME, NETWORK_INFO_NAME, AGENT_KEY);
-        relationships.add(agentConfigToNetworkInfo);
-        Relationship agentConfigToVmGcStat = new Relationship(AGENT_CONFIG_NAME, VM_GC_STAT_NAME, AGENT_KEY);
-        relationships.add(agentConfigToVmGcStat);
-        Relationship agentConfigToHostInfo = new Relationship(AGENT_CONFIG_NAME, HOST_INFO_NAME, AGENT_KEY);
-        relationships.add(agentConfigToHostInfo);
-        Relationship agentConfigToVmInfo = new Relationship(AGENT_CONFIG_NAME, VM_INFO_NAME, AGENT_KEY);
-        relationships.add(agentConfigToVmInfo);
-        Relationship vmInfoToVmGcStat = new Relationship(VM_INFO_NAME, VM_GC_STAT_NAME, VM_KEY);
-        relationships.add(vmInfoToVmGcStat);
-        return relationships;
-    }
-
-    private List<ConfigItem> buildGoodRecords() {
-        List<ConfigItem> records = new ArrayList<>();
-        ConfigItem agentConfig = new ConfigItem(10, 3, AGENT_CONFIG_NAME);
-        records.add(agentConfig);
-        ConfigItem hostInfo = new ConfigItem(3, 0, HOST_INFO_NAME);
-        records.add(hostInfo);
-        ConfigItem networkInfo = new ConfigItem(100, 0, NETWORK_INFO_NAME);
-        records.add(networkInfo);
-        ConfigItem vmGcStat = new ConfigItem(23, 0, VM_GC_STAT_NAME);
-        records.add(vmGcStat);
-        ConfigItem vmInfo = new ConfigItem(10, 0, VM_INFO_NAME);
-        records.add(vmInfo);
-        return records;
-    }
-
-    /**
-     * Tests topological sorting with a cycle. Expected to fail.
-     */
-    @Test(expected = AssertionError.class)
-    public void testTopogicalSortCycle() throws IOException {
-        List<ConfigItem> records = buildGoodRecords();
-        List<Relationship> rels = buildGoodRels();
-        // add a cycle between vm-info -> host-info -> agent-config
-        Relationship cyclePartOne = new Relationship(VM_INFO_NAME, HOST_INFO_NAME, VM_KEY);
-        rels.add(cyclePartOne);
-        Relationship cyclePartTwo = new Relationship(HOST_INFO_NAME, AGENT_CONFIG_NAME, AGENT_KEY);
-        rels.add(cyclePartTwo);
-        PopulationConfig pc = PopulationConfig.createFromLists(records, rels);
-        // This is expected to fail
-        pc.getConfigsTopologicallySorted();
-    }
-    
-    @Test(expected = PopulationConfig.InvalidConfigurationException.class)
-    public void testTopogicalSortIncomingCollectionMissing() throws IOException {
-        List<ConfigItem> records = buildGoodRecords();
-        // remove vm-gc-stat records config which has an incoming edge
-        // from agent-config and vm-info
-        int deleteIdx = -1;
-        for (int i = 0; i < records.size(); i++) {
-            ConfigItem item = records.get(i);
-            if (item.getName().equals(VM_GC_STAT_NAME)) {
-                deleteIdx = i;
-                break;
-            }
-        }
-        assertTrue("Expected vm-gc-stat to be in records config", deleteIdx >= 0);
-        records.remove(deleteIdx);
-        List<Relationship> rels = buildGoodRels();
-        PopulationConfig pc = PopulationConfig.createFromLists(records, rels);
-        pc.getConfigsTopologicallySorted();
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/typeadapter/ConfigItemTypeAdapterTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-
-public class ConfigItemTypeAdapterTest {
-
-    private Gson gson;
-    
-    @Before
-    public void setup() {
-        gson= new GsonBuilder()
-                .registerTypeAdapter(ConfigItem.class, new ConfigItemTypeAdapter())
-                .create();
-    }
-    
-    @Test
-    public void testBasicNonNull() {
-        ConfigItem item = gson.fromJson("{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}", ConfigItem.class);
-        assertEquals("config-item", item.getName());
-        assertEquals(3, item.getNumber());
-        assertEquals(1, item.getAliveItems());
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void testBasicNegativeNumber() {
-        gson.fromJson("{ \"name\": \"config-item\", \"number\": -3, \"alive\": 1}", ConfigItem.class);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void testBasicNegativeAlive() {
-        gson.fromJson("{ \"name\": \"config-item\", \"number\": 10, \"alive\": -1}", ConfigItem.class);
-    }
-    
-    @Test(expected = IllegalArgumentException.class)
-    public void testBasicAliveGreaterThanNumber() {
-        // alive > number. Expected strict subset
-        gson.fromJson("{ \"name\": \"config-item\", \"number\": 10, \"alive\": 11}", ConfigItem.class);
-    }
-    
-    @Test
-    public void testBasicNullAlive() {
-        ConfigItem item = gson.fromJson("{ \"name\": \"config-item\", \"number\": 3}", ConfigItem.class);
-        assertEquals("config-item", item.getName());
-        assertEquals(3, item.getNumber());
-        assertEquals(ConfigItem.UNSET, item.getAliveItems());
-    }
-    
-    @Test
-    public void testArray() {
-        ConfigItem[] items = gson.fromJson("[{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}," +
-                "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]", ConfigItem[].class);
-        assertEquals("config-item", items[0].getName());
-        assertEquals(3, items[0].getNumber());
-        assertEquals(1, items[0].getAliveItems());
-        assertEquals("agent-config", items[1].getName());
-        assertEquals(10, items[1].getNumber());
-        assertEquals(3, items[1].getAliveItems());
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/typeadapter/PopulationConfigTypeAdapterTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.config.PopulationConfig;
-import com.redhat.thermostat.dev.populator.dependencies.Relationship;
-
-public class PopulationConfigTypeAdapterTest {
-
-    private Gson gson;
-    
-    @Before
-    public void setup() {
-        gson= new GsonBuilder()
-                .registerTypeAdapter(Relationship.class, new RelationShipTypeAdapter())
-                .registerTypeAdapter(ConfigItem.class, new ConfigItemTypeAdapter())
-                .registerTypeAdapterFactory(new PopulationConfigTypeAdapterFactory())
-                .create();
-    }
-    
-    @Test
-    public void canParseSimpleNoRelationships() throws Exception {
-        String json = "{ \"records\": " +
-                "[{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}," +
-                "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]" +
-                "}";
-        PopulationConfig config = gson.fromJson(json, PopulationConfig.class);
-        ConfigItem item = config.getConfig("config-item");
-        assertEquals(3, item.getNumber());
-        assertEquals(1, item.getAliveItems());
-        assertEquals("config-item", item.getName());
-        item = config.getConfig("agent-config");
-        assertEquals(10, item.getNumber());
-        assertEquals(3, item.getAliveItems());
-        assertEquals("agent-config", item.getName());
-    }
-    
-    @Test
-    public void canParseSimpleWithRelationships() throws Exception {
-        String json = "{ \"records\": " +
-                "[{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}," +
-                "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]," +
-                " \"relationships\": "+
-                "[{ \"from\": \"config-item\", \"to\": \"agent-config\", \"key\": \"foo\"}]" +
-                "}";
-        PopulationConfig config = gson.fromJson(json, PopulationConfig.class);
-        ConfigItem item = config.getConfig("config-item");
-        assertEquals(3, item.getNumber());
-        assertEquals(1, item.getAliveItems());
-        assertEquals("config-item", item.getName());
-        item = config.getConfig("agent-config");
-        assertEquals(10, item.getNumber());
-        assertEquals(3, item.getAliveItems());
-        assertEquals("agent-config", item.getName());
-        // Do something that uses relationships
-        List<ConfigItem> sorted = config.getConfigsTopologicallySorted();
-        ConfigItem first = sorted.get(0);
-        assertEquals("config-item", first.getName());
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/config/typeadapter/RelationShipTypeAdapterTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.config.typeadapter;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.redhat.thermostat.dev.populator.dependencies.Relationship;
-
-public class RelationShipTypeAdapterTest {
-
-    private Gson gson;
-    
-    @Before
-    public void setup() {
-        gson= new GsonBuilder()
-                .registerTypeAdapter(Relationship.class, new RelationShipTypeAdapter())
-                .create();
-    }
-    
-    @Test
-    public void testBasicNonNull() {
-        Relationship rel = gson.fromJson("{ \"from\": \"foo\", \"to\": \"bar\", \"key\": \"baz\"}", Relationship.class);
-        assertEquals("foo", rel.getFrom());
-        assertEquals("bar", rel.getTo());
-        assertEquals("baz", rel.getKey());
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/dependencies/RelationshipTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.dependencies;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class RelationshipTest {
-
-    @Test
-    public void testEquals() {
-        Relationship one = new Relationship("foo", "bar", "key");
-        Relationship two = new Relationship("foo", "bar", "key");
-        Relationship different = new Relationship("foo", "bar", "something");
-        assertTrue(one.equals(two));
-        assertTrue(one.equals(one));
-        assertFalse(one.equals(different));
-        assertFalse(one.equals(null));
-        assertTrue(two.equals(one));
-    }
-    
-    @Test
-    public void testHashCode() {
-        Relationship one = new Relationship("foo", "bar", "key");
-        Relationship two = new Relationship("foo", "bar", "key");
-        Relationship different = new Relationship("foo", "bar", "something");
-        assertEquals(one.hashCode(), two.hashCode());
-        assertFalse(different.hashCode() == one.hashCode());
-        assertFalse(two.hashCode() == different.hashCode());
-        assertEquals(one.hashCode(), one.hashCode());
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/AgentInfoPopulatorTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class AgentInfoPopulatorTest {
-
-    @Test
-    public void canHandleAgentInfoCollection() {
-        AgentInfoPopulator putter = new AgentInfoPopulator();
-        assertEquals("agent-config", putter.getHandledCollection());
-    }
-    
-    @Test
-    public void canAddPojos() {
-        int totalRecords = 23;
-        AgentInfoDAO dao = mock(AgentInfoDAO.class);
-        // Initially return 0, then return the expected count
-        when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
-        AgentInfoPopulator putter = new AgentInfoPopulator(dao);
-        ConfigItem item = new ConfigItem(totalRecords, 3, "agent-config");
-        SharedState state = new SharedState();
-        state = putter.addPojos(mock(Storage.class), item, state);
-        ArgumentCaptor<AgentInformation> agentInfoCaptor = ArgumentCaptor.forClass(AgentInformation.class);
-        verify(dao, times(23)).addAgentInformation(agentInfoCaptor.capture());
-        List<AgentInformation> agentInfos = agentInfoCaptor.getAllValues();
-        List<AgentInformation> filtered = getAliveAgentInfos(agentInfos);
-        assertEquals(3, filtered.size());
-        ProcessedRecords<String> recs = state.getProcessedRecordsFor("agentId");
-        assertEquals(23, recs.getAll().size());
-        ProcessedRecords<String> notExisting = state.getProcessedRecordsFor("foo-bar");
-        assertNull(notExisting);
-        // FIXME: HostInfo populator needs AgentInfoDAO so we tag the dao
-        //        to the shared state. This test asserts that it does so.
-        AgentInfoDAO stateDAO = (AgentInfoDAO)state.getProperty("agent-info-dao");
-        assertNotNull(stateDAO);
-        assertSame(stateDAO, dao);
-    }
-
-    private List<AgentInformation> getAliveAgentInfos(List<AgentInformation> agentInfos) {
-        List<AgentInformation> aliveInfos = new ArrayList<>();
-        for (AgentInformation info: agentInfos) {
-            if (info.isAlive()) {
-                aliveInfos.add(info);
-            }
-        }
-        return aliveInfos;
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/HostInfoPopulatorTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.model.HostInfo;
-
-public class HostInfoPopulatorTest {
-
-    @Test
-    public void handlesCorrectCollection() {
-        HostInfoPopulator populator = new HostInfoPopulator();
-        assertEquals("host-info", populator.getHandledCollection());
-    }
-    
-    @Test
-    public void canPopulateToStorage() {
-        String[] agents = new String[] {
-                "host-agent1", "host-agent2", "host-agent3", "host-agent4"
-        };
-        List<String> agentIds = Arrays.asList(agents);
-        SharedState state = mock(SharedState.class);
-        @SuppressWarnings("unchecked")
-        ProcessedRecords<String> procRecs = mock(ProcessedRecords.class);
-        when(procRecs.getAll()).thenReturn(agentIds);
-        when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs);
-        when(state.getProperty(eq("agent-info-dao"))).thenReturn(mock(AgentInfoDAO.class));
-        int totalRecords = agents.length;
-        HostInfoDAO dao = mock(HostInfoDAO.class);
-        // Initially return 0, then return the expected count
-        when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
-        
-        ConfigItem config = new ConfigItem(1, ConfigItem.UNSET, "host-info");
-        HostInfoPopulator populator = new HostInfoPopulator(dao);
-        populator.addPojos(mock(Storage.class), config, state);
-        ArgumentCaptor<HostInfo> captor = ArgumentCaptor.forClass(HostInfo.class);
-        verify(dao, times(totalRecords)).putHostInfo(captor.capture());
-        List<HostInfo> values = captor.getAllValues();
-        // ensure no memory values are negative
-        for (HostInfo info: values) {
-            if (info.getTotalMemory() < 0) {
-                throw new AssertionError("Invalid memory value: " + info.getTotalMemory() + " < 0");
-            }
-        }
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/NetworkInfoPopulatorTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.dev.populator.internal.NetworkInfoPopulator.NetworkInterfaceDAOCountable;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
-
-public class NetworkInfoPopulatorTest {
-
-    @Test
-    public void canHandleCorrectCollection() {
-        NetworkInfoPopulator populator = new NetworkInfoPopulator();
-        assertEquals("network-info", populator.getHandledCollection());
-    }
-    
-    @Test
-    public void testPopulation() {
-        NetworkInterfaceDAOCountable dao = mock(NetworkInterfaceDAOCountable.class);
-        NetworkInfoPopulator populator = new NetworkInfoPopulator(dao);
-        
-        String[] agentIds = new String[] {
-                "testAgent1", "testAgent2", "testAgent3", "testAgent4"
-        };
-        int perAgentItems = 100;
-        int totalRecords = perAgentItems * agentIds.length;
-        when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
-        List<String> agents = Arrays.asList(agentIds);
-        SharedState state = new SharedState();
-        state.addProcessedRecords("agentId", new ProcessedRecords<>(agents));
-        ConfigItem config = new ConfigItem(perAgentItems, ConfigItem.UNSET, "network-info");
-        populator.addPojos(mock(Storage.class), config, state);
-        ArgumentCaptor<NetworkInterfaceInfo> captor = ArgumentCaptor.forClass(NetworkInterfaceInfo.class);
-        verify(dao, times(totalRecords)).putNetworkInterfaceInfo(captor.capture());
-        List<NetworkInterfaceInfo> list = captor.getAllValues();
-        // expected agentId + iface name to be unique (since REPLACE otherwise replaces some random values)
-        Set<String> uniqueSet = new HashSet<>();
-        for (NetworkInterfaceInfo info: list) {
-            String agentId = info.getAgentId();
-            String ifaceName = info.getInterfaceName();
-            String key = agentId + ifaceName;
-            if (uniqueSet.contains(key)) {
-                throw new AssertionError("Expected interface names to be unique per agent");
-            } else {
-                uniqueSet.add(key);
-            }
-        }
-    }
-    
-    @Test
-    public void iPv6HextetRollOver() {
-        String ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("fffe", 16));
-        assertEquals("fffe", ipv6);
-        ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("ffff", 16));
-        assertEquals("1", ipv6);
-        ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("eee1", 16));
-        assertEquals("eee1", ipv6);
-    }
-    
-    @Test
-    public void iPv4OctetsRollOver() {
-        int octet = new NetworkInfoPopulator().getIpv4Octet(255);
-        assertEquals(1, octet);
-        octet = new NetworkInfoPopulator().getIpv4Octet(256);
-        assertEquals(1, octet);
-        octet = new NetworkInfoPopulator().getIpv4Octet(114);
-        assertEquals(114, octet);
-    }
-    
-    @Test
-    public void stringFormatIpv6Template() {
-        String formattedString = String.format(NetworkInfoPopulator.IPV6_FORMATS[1], "ff", "scope");
-        assertEquals("fe80::56ee:75ff:fe35:ff%scope", formattedString);
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/ThreadPopulatorTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.dev.populator.internal.ThreadPopulator.ThreadDaoCountable;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.BasePojo;
-import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
-import com.redhat.thermostat.thread.model.ThreadSession;
-import com.redhat.thermostat.thread.model.ThreadState;
-import com.redhat.thermostat.thread.model.ThreadSummary;
-import com.redhat.thermostat.thread.model.VmDeadLockData;
-
-public class ThreadPopulatorTest {
-    
-    private static final String EXPECTED_DESCRIPTION = "" +
-            "\"Mallory\" Id=12 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"Alice\" Id=10\n" +
-            "\tat sun.misc.Unsafe.park(Native Method)\n" +
-            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
-            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
-            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
-            "\t...\n\n" +
-            "\tNumber of locked synchronizers = 1\n" +
-            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2" +
-            "\n\n\n" +
-            "\"Alice\" Id=10 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"Bob\" Id=11\n" +
-            "\tat sun.misc.Unsafe.park(Native Method)\n" +
-            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + 
-            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + 
-            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
-            "\t...\n\n" + 
-            "\tNumber of locked synchronizers = 1\n" +
-            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
-            "\n\n" +
-            "\"Bob\" Id=11 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"Mallory\" Id=12\n" +
-            "\tat sun.misc.Unsafe.park(Native Method)\n" +
-            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" +
-            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + 
-            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + 
-            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
-            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
-            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + 
-            "\t...\n\n" +
-            "\tNumber of locked synchronizers = 1\n" +
-            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n";
-
-    private static final String[] AGENTS = new String[] {
-            "fooAgent1", "fooBarAgent", "testAgent", "someAgent"
-    };
-    private static final String[] VMS = new String[] {
-            "vm1", "vm2", "vm3", "vm4", "vm5"
-    };
-
-    private ThreadDaoCountable countableDao;
-    
-    @Test
-    public void testFormatDeadlockDesc() {
-        Object[] stringFormatArgs = new Object[] {
-                "Mallory", 12,
-                "Alice", 10,
-                "Alice", 10,
-                "Bob", 11,
-                "Bob", 11,
-                "Mallory", 12
-        };
-        assertEquals(EXPECTED_DESCRIPTION, String.format(ThreadPopulator.DEADLOCK_DESC_FORMAT, stringFormatArgs));
-    }
-    
-    @Test
-    public void canGetRandomThreadNames() {
-        Object[] args = new ThreadPopulator().getFormatStringArgs(2);
-        assertEquals(12, args.length);
-        Map<Integer, Integer> tids = new HashMap<>();
-        Map<String, Integer> threadNames = new HashMap<>();
-        for (int i = 0; i < args.length; i +=2) {
-            Object arg1 = args[i];
-            Object arg2 = args[i + 1];
-            assertEquals(String.class, arg1.getClass());
-            assertEquals(Integer.class, arg2.getClass());
-            if (tids.containsKey(arg2)) {
-                Integer value = tids.get(arg2);
-                value += 1;
-                tids.put((Integer)arg2, value);
-            } else {
-                tids.put((Integer)arg2, 1);
-            }
-            if (threadNames.containsKey(arg1)) {
-                Integer value = threadNames.get(arg1);
-                value += 1;
-                threadNames.put((String)arg1, value);
-            } else {
-                threadNames.put((String)arg1, 1);
-            }
-        }
-        for (String key : threadNames.keySet()) {
-            int value = threadNames.get(key);
-            assertEquals(2, value);
-        }
-        for (Integer key : tids.keySet()) {
-            int value = tids.get(key);
-            assertEquals(2, value);
-        }
-    }
-
-    @Test
-    public void canHandleAppropriateCollection() {
-        ThreadPopulator populator = new ThreadPopulator();
-        assertEquals("vm-thread-harvesting", populator.getHandledCollection());
-    }
-
-    @Test
-    public void canAddThreadData() {
-        int perVmCount = 123;
-        int totalCount = perVmCount * AGENTS.length * VMS.length;
-        setUp(perVmCount, totalCount);
-
-        assertThreadSummaries(totalCount, perVmCount);
-        assertThreadSessions(totalCount, perVmCount);
-        assertThreadStates(totalCount, perVmCount);
-        assertThreadHarvestingStatus(totalCount, perVmCount);
-        assertDeadlockInfo(perVmCount, totalCount);
-    }
-
-    private void setUp(int perVmCount, int totalCount) {
-        ConfigItem config = new ConfigItem(perVmCount, ConfigItem.UNSET, "vm-deadlock-data");
-        countableDao = mock(ThreadDaoCountable.class);
-        when(countableDao.getCount()).thenReturn(0L).thenReturn((long)totalCount);
-        ThreadPopulator populator = new ThreadPopulator(countableDao);
-        SharedState state = mock(SharedState.class);
-        when(state.getProcessedRecordsFor("agentId")).thenReturn(new ProcessedRecords<>(Arrays.asList(AGENTS)));
-        when(state.getProcessedRecordsFor("vmId")).thenReturn(new ProcessedRecords<>(Arrays.asList(VMS)));
-        SharedState retval = populator.addPojos(mock(Storage.class), config, state);
-        assertSame(retval, state);
-    }
-
-    private void assertThreadSummaries(int totalCount, int perVmCount) {
-        ArgumentCaptor<ThreadSummary> summaryCaptor = ArgumentCaptor.forClass(ThreadSummary.class);
-        verify(countableDao, times(totalCount)).saveSummary(summaryCaptor.capture());
-        List<ThreadSummary> savedValues = summaryCaptor.getAllValues();
-        assertEquals(totalCount, savedValues.size());
-        checkInstances(savedValues, VMS.length * perVmCount);
-    }
-
-    private void assertThreadSessions(int totalCount, int perVmCount) {
-        ArgumentCaptor<ThreadSession> sessionCaptor = ArgumentCaptor.forClass(ThreadSession.class);
-        verify(countableDao, times(totalCount)).saveSession(sessionCaptor.capture());
-        List<ThreadSession> savedValues = sessionCaptor.getAllValues();
-        assertEquals(totalCount, savedValues.size());
-        checkInstances(savedValues, VMS.length * perVmCount);
-    }
-
-    private void assertThreadStates(int totalCount, int perVmCount) {
-        ArgumentCaptor<ThreadState> stateCaptor = ArgumentCaptor.forClass(ThreadState.class);
-        verify(countableDao, times(totalCount * ThreadPopulator.NUM_SAMPLES)).
-                addThreadState(stateCaptor.capture());
-        List<ThreadState> savedValues = stateCaptor.getAllValues();
-        assertEquals(totalCount * ThreadPopulator.NUM_SAMPLES, savedValues.size());
-        checkInstances(savedValues, VMS.length * perVmCount * ThreadPopulator.NUM_SAMPLES);
-    }
-
-    private void assertThreadHarvestingStatus(int totalCount, int perVmCount) {
-        ArgumentCaptor<ThreadHarvestingStatus> statusCaptor =
-                ArgumentCaptor.forClass(ThreadHarvestingStatus.class);
-        verify(countableDao, times(totalCount)).saveHarvestingStatus(statusCaptor.capture());
-        List<ThreadHarvestingStatus> savedValues = statusCaptor.getAllValues();
-        checkInstances(savedValues, VMS.length * perVmCount);
-    }
-
-    private void checkInstances(List<? extends BasePojo> savedValues, int expected) {
-        List<String> agentIds = new ArrayList<>();
-        for (int i = 0; i < savedValues.size(); i++) {
-            agentIds.add(savedValues.get(i).getAgentId());
-        }
-
-        for (String agentId : AGENTS) {
-            int numInstances = Collections.frequency(agentIds, agentId);
-            assertEquals(expected, numInstances);
-        }
-    }
-
-    private void assertDeadlockInfo(int perVmCount, int totalCount) {
-        ArgumentCaptor<VmDeadLockData> deadlockInfoCaptor = ArgumentCaptor.forClass(VmDeadLockData.class);
-        verify(countableDao, times(totalCount)).saveDeadLockStatus(deadlockInfoCaptor.capture());
-        List<VmDeadLockData> savedValues = deadlockInfoCaptor.getAllValues();
-        assertEquals(totalCount, savedValues.size());
-        List<VmDeadLockData> perVmIdAgentDeadlockData = getFilteredByVmId(savedValues, "vm3");
-        assertEquals(perVmCount * AGENTS.length, perVmIdAgentDeadlockData.size());
-        List<VmDeadLockData> perAgentIdDeadlockData = getFilteredByAgentId(savedValues, "fooAgent1");
-        verifyVmIdsDifferent(perAgentIdDeadlockData);
-    }
-
-    private List<VmDeadLockData> getFilteredByAgentId(List<VmDeadLockData> perVmDeadlockData, String agentId) {
-        List<VmDeadLockData> filteredValues = new ArrayList<>();
-        for (VmDeadLockData data: perVmDeadlockData) {
-            if (data.getAgentId().equals(agentId)) {
-                filteredValues.add(data);
-            }
-        }
-        return filteredValues;
-    }
-
-    private void verifyVmIdsDifferent(List<VmDeadLockData> perVmDeadlockData) {
-        Set<String> vmIds = new HashSet<>();
-        for (VmDeadLockData data: perVmDeadlockData) {
-            if (vmIds.contains(data.getVmId())) {
-                throw new AssertionError("Duplicate VM ID per agent. Duplicate was: " + data.getVmId());
-            }
-            vmIds.add(data.getAgentId());
-        }
-    }
-
-    private List<VmDeadLockData> getFilteredByVmId(List<VmDeadLockData> savedValues, String vmId) {
-        List<VmDeadLockData> filteredValues = new ArrayList<>();
-        for (VmDeadLockData data: savedValues) {
-            if (data.getVmId().equals(vmId)) {
-                filteredValues.add(data);
-            }
-        }
-        return filteredValues;
-    }
-}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/VmInfoPopulatorTest.java	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012-2016 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.dev.populator.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.dev.populator.config.ConfigItem;
-import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords;
-import com.redhat.thermostat.dev.populator.dependencies.SharedState;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-
-public class VmInfoPopulatorTest {
-
-    @Test
-    public void canHandleCorrectCollection() {
-        VmInfoPopulator populator = new VmInfoPopulator();
-        assertEquals("vm-info", populator.getHandledCollection());
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void canPopulateData() {
-        VmInfoDAO mockDAO = mock(VmInfoDAO.class);
-        SharedState state = mock(SharedState.class);
-        ProcessedRecords<String> procRecs = mock(ProcessedRecords.class);
-        String[] agents = new String[] {
-                "foo-agent1", "foo-agent2", "bar-agent3"
-        };
-        List<String> agentIdList = Arrays.asList(agents);
-        when(procRecs.getAll()).thenReturn(agentIdList);
-        when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs);
-        int perAgentVms = 44;
-        int subsetAlive = 23;
-        ConfigItem config = new ConfigItem(perAgentVms, subsetAlive, "vm-info");
-        
-        // total records inserted will be 3 * 44. 44 records per agentId
-        int totalRecords = perAgentVms * agents.length;
-        // Initially return 0, then return the expected count
-        when(mockDAO.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
-        VmInfoPopulator populator = new VmInfoPopulator(mockDAO);
-        populator.addPojos(mock(Storage.class), config, state);
-        ArgumentCaptor<VmInfo> captor = ArgumentCaptor.forClass(VmInfo.class);
-        verify(mockDAO, times(totalRecords)).putVmInfo(captor.capture());
-        List<VmInfo> allInfos = captor.getAllValues();
-        assertEquals(totalRecords, allInfos.size());
-        List<VmInfo> aliveInfos = getAliveVmInfos(allInfos);
-        int totalAliveRecs = subsetAlive * agents.length;
-        assertEquals(totalAliveRecs, aliveInfos.size());
-        @SuppressWarnings("rawtypes")
-        ArgumentCaptor<ProcessedRecords> procsVms = ArgumentCaptor.forClass(ProcessedRecords.class);
-        verify(state).addProcessedRecords(eq("vmId"), procsVms.capture());
-        ProcessedRecords<String> processedVms = procsVms.getValue();
-        assertEquals("Excected vmIds added to shared state", totalRecords, processedVms.getAll().size());
-    }
-    
-    @SuppressWarnings("deprecation")
-    private List<VmInfo> getAliveVmInfos(List<VmInfo> allInfos) {
-        List<VmInfo> aliveInfos = new ArrayList<>();
-        for (VmInfo info: allInfos) {
-            if (info.isAlive()) {
-                aliveInfos.add(info);
-            }
-        }
-        return aliveInfos;
-    }
-}
--- a/dev/data-populator/src/test/resources/testconfig	Wed May 04 17:30:06 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-{
-"records":
-[
-{
- "name": "vm-gc-stats",
- "number": 1000,
- "alive": 1000
-},
-{
- "name": "agent-config",
- "number": 100,
- "alive": 20
-},
-{
- "name": "host-info",
- "number": 10
-},
-{
- "name": "cpu-stats",
- "number": 50000
-},
-{
- "name": "memory-stats",
- "number": 50000
-},
-{
- "name": "network-info",
- "number": 4
-},
-{
- "name": "vm-info",
- "number": 50,
- "alive": 40
-}
-],
-"relationships":
-[
-{ "from": "agent-config",
-  "to": "vm-info",
-  "key": "agentId"
-},
-{ "from": "agent-config",
-  "to": "host-info",
-  "key": "agentId"
-},
-{ "from": "agent-config",
-  "to": "network-info",
-  "key": "agentId"
-},
-{ "from": "vm-info",
-  "to": "vm-gc-stats",
-  "key": "vmId"
-}
-]
-}
\ No newline at end of file
--- a/dev/pom.xml	Wed May 04 17:30:06 2016 +0200
+++ b/dev/pom.xml	Thu May 05 10:37:43 2016 -0400
@@ -56,7 +56,7 @@
     <module>ide-launcher</module>
     <module>schema-info-command</module>
     <module>perflog-analyzer</module>
-    <module>data-populator</module>
+    <module>storage-populator</module>
     <module>ipc-test</module>
   </modules>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/pom.xml	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-storage-populator</artifactId>
+    <version>1.99.10-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-storage-populator-command</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Storage populator</name>
+  <url>${project.parent.url}</url>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>com.redhat.thermostat.storage.populator</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-Activator>com.redhat.thermostat.storage.populator.internal.Activator</Bundle-Activator>
+            <Export-Package>
+                com.redhat.thermostat.storage.populator,
+            </Export-Package>
+            <Private-Package>
+              com.redhat.thermostat.storage.populator.internal,
+              com.redhat.thermostat.storage.populator.internal.config,
+              com.redhat.thermostat.storage.populator.internal.config.typeadapter,
+              com.redhat.thermostat.storage.populator.internal.dependencies,
+            </Private-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.framework</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-storage-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-thread-collector</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>com.google.code.gson</groupId>
+        <artifactId>gson</artifactId>
+        <version>${gson.version}</version>
+    </dependency>
+  </dependencies>
+
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommand.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.cli.AbstractCommand;
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.common.cli.DependencyServices;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.dao.HostInfoDAO;
+import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+import com.redhat.thermostat.storage.populator.internal.AgentInfoPopulator;
+import com.redhat.thermostat.storage.populator.internal.CollectionPopulator;
+import com.redhat.thermostat.storage.populator.internal.HostInfoPopulator;
+import com.redhat.thermostat.storage.populator.internal.NetworkInfoPopulator;
+import com.redhat.thermostat.storage.populator.internal.ThreadPopulator;
+import com.redhat.thermostat.storage.populator.internal.VmInfoPopulator;
+import com.redhat.thermostat.storage.populator.internal.LocaleResources;
+import com.redhat.thermostat.thread.dao.ThreadDao;
+
+public class StoragePopulatorCommand extends AbstractCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    private static final Logger logger = LoggingUtils.getLogger(StoragePopulatorCommand.class);
+
+    private static final String CONFIG_FILE_NAME = "config";
+
+    private final Map<String, CollectionPopulator> populators = new HashMap<>();
+    private final DependencyServices dependencyServices = new DependencyServices();
+
+    private CommonPaths paths;
+    private HostInfoDAO hostInfoDAO;
+    private AgentInfoDAO agentInfoDAO;
+    private VmInfoDAO vmInfoDAO;
+    private NetworkInterfaceInfoDAO networkInfoDAO;
+    private ThreadDao threadDao;
+
+    private Console console;
+
+    public void setPaths(CommonPaths paths) {
+        dependencyServices.addService(CommonPaths.class, paths);
+    }
+
+    public void setHostInfoDAO(HostInfoDAO dao) {
+        dependencyServices.addService(HostInfoDAO.class, dao);
+    }
+
+    public void setAgentInfoDAO(AgentInfoDAO dao) {
+        dependencyServices.addService(AgentInfoDAO.class, dao);
+    }
+
+    public void setVmInfoDAO(VmInfoDAO dao) {
+        dependencyServices.addService(VmInfoDAO.class, dao);
+    }
+
+    public void setNetworkInfoDAO(NetworkInterfaceInfoDAO dao) {
+        dependencyServices.addService(NetworkInterfaceInfoDAO.class, dao);
+    }
+
+    public void setThreadDao(ThreadDao dao) {
+        dependencyServices.addService(ThreadDao.class, dao);
+    }
+
+    public void setServicesUnavailable() {
+        dependencyServices.removeService(CommonPaths.class);
+        dependencyServices.removeService(HostInfoDAO.class);
+        dependencyServices.removeService(AgentInfoDAO.class);
+        dependencyServices.removeService(VmInfoDAO.class);
+        dependencyServices.removeService(NetworkInterfaceInfoDAO.class);
+        dependencyServices.removeService(ThreadDao.class);
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        console = ctx.getConsole();
+
+        paths = dependencyServices.getService(CommonPaths.class);
+        requireNonNull(paths,
+                translator.localize(LocaleResources.COMMON_PATHS_SERVICE_UNAVAILABLE));
+
+        hostInfoDAO = dependencyServices.getService(HostInfoDAO.class);
+        requireNonNull(hostInfoDAO, translator.localize(LocaleResources.HOST_SERVICE_UNAVAILABLE));
+
+        agentInfoDAO = dependencyServices.getService(AgentInfoDAO.class);
+        requireNonNull(agentInfoDAO,
+                translator.localize(LocaleResources.AGENT_SERVICE_UNAVAILABLE));
+
+        vmInfoDAO = dependencyServices.getService(VmInfoDAO.class);
+        requireNonNull(vmInfoDAO, translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
+
+        networkInfoDAO = dependencyServices.getService(NetworkInterfaceInfoDAO.class);
+        requireNonNull(networkInfoDAO,
+                translator.localize(LocaleResources.NETWORK_SERVICE_UNAVAILABLE));
+
+        threadDao = dependencyServices.getService(ThreadDao.class);
+        requireNonNull(threadDao, translator.localize(LocaleResources.THREAD_SERVICE_UNAVAILABLE));
+
+        HostInfoPopulator hostInfoPopulator = new HostInfoPopulator(hostInfoDAO);
+        populators.put(hostInfoPopulator.getHandledCollection(), hostInfoPopulator);
+
+        AgentInfoPopulator agentInfoPopulator = new AgentInfoPopulator(agentInfoDAO);
+        populators.put(agentInfoPopulator.getHandledCollection(), agentInfoPopulator);
+
+        VmInfoPopulator vmInfoPopulator = new VmInfoPopulator(vmInfoDAO);
+        populators.put(vmInfoPopulator.getHandledCollection(), vmInfoPopulator);
+
+        NetworkInfoPopulator networkInfoPopulator = new NetworkInfoPopulator(networkInfoDAO);
+        populators.put(networkInfoPopulator.getHandledCollection(), networkInfoPopulator);
+
+        ThreadPopulator threadPopulator = new ThreadPopulator(threadDao);
+        populators.put(threadPopulator.getHandledCollection(), threadPopulator);
+
+        try {
+            PopulationConfig config = getPopulationConfigFromArg(ctx.getArguments());
+            addItemsToStorage(config);
+        } catch (IllegalArgumentException e) {
+            console.getError().println(e.getLocalizedMessage());
+        }
+    }
+
+    private PopulationConfig getPopulationConfigFromArg(Arguments args) {
+        File configFile = getConfigFile(args);
+        if (!configFile.exists()) {
+            throw new IllegalArgumentException(translator.localize(
+                    LocaleResources.NONEXISTENT_CONFIG, configFile.getAbsolutePath()).getContents());
+        }
+        String json;
+        PopulationConfig config;
+        try {
+            json = new String(Files.readAllBytes(configFile.toPath()));
+            config = PopulationConfig.parseFromJsonString(json);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(
+                    translator.localize(LocaleResources.CONFIG_PARSING_FAILED).getContents(), e);
+        }
+
+        return config;
+    }
+
+    /**
+     * Package-private to allow overriding for testing.
+     */
+    File getConfigFile(Arguments args) {
+        return new File(paths.getSystemPluginConfigurationDirectory().getAbsolutePath() +
+                    "/storage-populator/" + args.getArgument(CONFIG_FILE_NAME));
+    }
+
+    /**
+     * Add items to storage in topologically sorted order so as to have
+     * relevant depending state available.
+     *
+     * @param config The configuration describing the records to be added
+     */
+    private void addItemsToStorage(PopulationConfig config) {
+        SharedState state = new SharedState();
+        for (ConfigItem item: config.getConfigsTopologicallySorted()) {
+            state = addRecordsForConfig(item, state);
+        }
+    }
+
+    private SharedState addRecordsForConfig(ConfigItem item, SharedState state) {
+        CollectionPopulator populator = populators.get(item.getName());
+        if (populator == null) {
+            throw new IllegalArgumentException(translator.localize(
+                    LocaleResources.NO_POPULATOR_FOUND, item.getName()).getContents());
+        } else {
+            return populator.addPojos(item, state, console);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/Activator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.dao.HostInfoDAO;
+import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.populator.StoragePopulatorCommand;
+import com.redhat.thermostat.thread.dao.ThreadDao;
+
+public class Activator implements BundleActivator {
+
+    private MultipleServiceTracker tracker;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+
+        final StoragePopulatorCommand command = new StoragePopulatorCommand();
+        Hashtable<String,String> properties = new Hashtable<>();
+        properties.put(Command.NAME, "storage-populator");
+        context.registerService(Command.class, command, properties);
+
+        Class<?>[] deps = new Class<?>[] {
+                CommonPaths.class,
+                HostInfoDAO.class,
+                AgentInfoDAO.class,
+                VmInfoDAO.class,
+                NetworkInterfaceInfoDAO.class,
+                ThreadDao.class,
+        };
+
+        tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() {
+
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
+                HostInfoDAO hostInfoDAO = (HostInfoDAO) services.get(HostInfoDAO.class.getName());
+                AgentInfoDAO agentInfoDAO = (AgentInfoDAO) services.get(AgentInfoDAO.class.getName());
+                VmInfoDAO vmInfoDAO = (VmInfoDAO) services.get(VmInfoDAO.class.getName());
+                NetworkInterfaceInfoDAO networkInfoDAO = (NetworkInterfaceInfoDAO)
+                        services.get(NetworkInterfaceInfoDAO.class.getName());
+                ThreadDao threadDao = (ThreadDao) services.get(ThreadDao.class.getName());
+
+                command.setPaths(paths);
+                command.setHostInfoDAO(hostInfoDAO);
+                command.setAgentInfoDAO(agentInfoDAO);
+                command.setVmInfoDAO(vmInfoDAO);
+                command.setNetworkInfoDAO(networkInfoDAO);
+                command.setThreadDao(threadDao);
+            }
+
+            @Override
+            public void dependenciesUnavailable() {
+                command.setServicesUnavailable();
+            }
+        });
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        tracker.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/AgentInfoPopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.model.AgentInformation;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class AgentInfoPopulator extends BasePopulator {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private AgentInfoDAO dao;
+    
+    public AgentInfoPopulator() {
+        this(null);
+    }
+
+    public AgentInfoPopulator(AgentInfoDAO dao) {
+        this.dao = dao;
+    }
+
+    @Override
+    public SharedState addPojos(ConfigItem item, SharedState state, Console console) {
+        Objects.requireNonNull(dao,
+                translator.localize(LocaleResources.DAO_NOT_INITIALIZED).getContents());
+        // Default to all alive, if unset
+        int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems();
+        List<String> processedRecords = new ArrayList<>(); 
+        long currentTime = System.currentTimeMillis();
+        long countBefore = getCount();
+        console.getOutput().println("\n" + translator.localize(LocaleResources.POPULATING_RECORDS,
+                Integer.toString(item.getNumber()), item.getName()).getContents());
+        int currCount = 0;
+        for (int i = 0; i < item.getNumber(); i++) {
+            AgentInformation agentInfo = new AgentInformation();
+            String agentId = UUID.randomUUID().toString();
+            processedRecords.add(agentId);
+            agentInfo.setAgentId(agentId);
+            agentInfo.setAlive(getAliveValue(aliveItems, i));
+            agentInfo.setConfigListenAddress(String.format("127.0.0.1:%d", i));
+            agentInfo.setStartTime(currentTime);
+            dao.addAgentInformation(agentInfo);
+            currCount++;
+        }
+        reportSubmitted(item, currCount, console);
+        doWaitUntilCount(countBefore + item.getNumber(), console, 200);
+        state.addProcessedRecords("agentId", new ProcessedRecords<>(processedRecords));
+        return state;
+    }
+
+    private boolean getAliveValue(int aliveItems, int i) {
+        if (i < aliveItems) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    long getCount() {
+        return dao.getCount();
+    }
+
+    @Override
+    public String getHandledCollection() {
+        return AgentInfoDAO.CATEGORY.getName();
+    }
+
+    public void setDAO(AgentInfoDAO dao) {
+        this.dao = dao;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/BasePopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+
+public abstract class BasePopulator implements CollectionPopulator {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    protected void doWaitUntilCount(long expectedCount, Console console, long sleepTime) {
+        console.getOutput().print(
+                translator.localize(LocaleResources.WAITING_FOR_ARRIVAL).getContents());
+        while (getCount() != expectedCount) {
+            try {
+                Thread.sleep(sleepTime);
+                console.getOutput().print("."); // report some progress
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+        console.getOutput().println(
+                translator.localize(LocaleResources.ITEMS_HAVE_ARRIVED).getContents());
+    }
+    
+    protected void reportSubmitted(ConfigItem item, int totalCount, Console console) {
+        console.getOutput().println(translator.localize(LocaleResources.RECORDS_SUBMITTED,
+                Integer.toString(totalCount), item.getName()).getContents());
+    }
+
+    abstract long getCount();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/CollectionPopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public interface CollectionPopulator {
+
+    SharedState addPojos(ConfigItem item, SharedState relState, Console console);
+    
+    String getHandledCollection();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/HostInfoPopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.dao.HostInfoDAO;
+import com.redhat.thermostat.storage.model.HostInfo;
+import com.redhat.thermostat.storage.populator.internal.BasePopulator;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+import com.redhat.thermostat.storage.populator.internal.LocaleResources;
+
+public class HostInfoPopulator extends BasePopulator {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String[] HOSTS_FORMAT = new String[] {
+            "vm-host-%06d", "prometheus-%06d", "saturn-%06d"
+    };
+    private static final String DOMAIN_FORMAT = "domain-%06d";
+    private static final String HOSTNAME_SUFFIX = "example.com";
+    private static final long MB = 1024 * 1024;
+
+    private HostInfoDAO dao;
+    
+    public HostInfoPopulator() {
+        this(null);
+    }
+
+    public HostInfoPopulator(HostInfoDAO dao) {
+        this.dao = dao;
+    }
+
+    @Override
+    public SharedState addPojos(ConfigItem item, SharedState relState, Console console) {
+        Objects.requireNonNull(dao,
+                translator.localize(LocaleResources.DAO_NOT_INITIALIZED).getContents());
+        List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll();
+        int totalItems = agentIds.size();
+        int currCount = 0;
+        long countBefore = getCount();
+        console.getOutput().println("\n" + translator.localize(LocaleResources.POPULATING_RECORDS,
+                Integer.toString(totalItems), item.getName()).getContents());
+        // There is a 1-to-1 correspondence between host-info and agents
+        for (int i = agentIds.size() - 1; i >= 0; i--) {
+            String agentId = agentIds.get(i);
+            HostInfo info = new HostInfo();
+            info.setAgentId(agentId);
+            info.setCpuCount(getRandomInt(50 + i));
+            info.setCpuModel("x86_64, data populator");
+            info.setHostname(getRandomHostName(i));
+            info.setOsKernel("4.2.3 data populator");
+            info.setOsName("Linux Random Flavor");
+            int memory = getRandomInt(500 + i);
+            info.setTotalMemory(memory * MB);
+            dao.putHostInfo(info);
+            currCount++;
+        }
+        reportSubmitted(item, currCount, console);
+        doWaitUntilCount(countBefore + totalItems, console, 200);
+        return relState;
+    }
+
+    private String getRandomHostName(int i) {
+        int index = getRandomInt(HOSTS_FORMAT.length);
+        String hostFormat = HOSTS_FORMAT[index] + "." + DOMAIN_FORMAT + "." + HOSTNAME_SUFFIX;
+        return String.format(hostFormat, i, i);
+    }
+
+    private int getRandomInt(int i) {
+        return (int)(Math.random() * i);
+    }
+
+    @Override
+    long getCount() {
+        return dao.getCount();
+    }
+
+    @Override
+    public String getHandledCollection() {
+        return HostInfoDAO.hostInfoCategory.getName();
+    }
+
+    public void setDAO(HostInfoDAO dao) {
+        this.dao = dao;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/LocaleResources.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import com.redhat.thermostat.shared.locale.Translate;
+
+
+public enum LocaleResources {
+
+    COMMON_PATHS_SERVICE_UNAVAILABLE,
+    HOST_SERVICE_UNAVAILABLE,
+    AGENT_SERVICE_UNAVAILABLE,
+    VM_SERVICE_UNAVAILABLE,
+    NETWORK_SERVICE_UNAVAILABLE,
+    THREAD_SERVICE_UNAVAILABLE,
+    DAO_NOT_INITIALIZED,
+    WAITING_FOR_ARRIVAL,
+    ITEMS_HAVE_ARRIVED,
+    RECORDS_SUBMITTED,
+    POPULATING_RECORDS,
+    NONEXISTENT_CONFIG,
+    CONFIG_PARSING_FAILED,
+    NO_POPULATOR_FOUND,
+    ;
+
+    static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.storage.populator.command.locale.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/NetworkInfoPopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class NetworkInfoPopulator extends BasePopulator {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    static final String[] IPV4_FORMATS = new String[] {
+            "192.168.0.%d", "10.33.4.%d", "89.15.93.%d"
+    };
+    static final String[] IPV6_FORMATS = new String[] {
+            "e8:b1:fc:d2:e3:%s%%%s", "fe80::56ee:75ff:fe35:%s%%%s",
+            "0:0:0:0:0:0:0:%s%%%s"
+    };
+    private final String[] IFACE_NAMES = new String[] {
+            "lo", "enp0s25", "tun0", "virbr0", "wlp4s0"
+    };
+    private static int IPv6Mod = Integer.parseInt("ffff", 16);
+    private static int IPv4Mod = 255;
+
+    private NetworkInterfaceInfoDAO dao;
+
+    public NetworkInfoPopulator() {
+        this(null);
+    }
+
+    public NetworkInfoPopulator(NetworkInterfaceInfoDAO dao) {
+        this.dao = dao;
+    }
+
+    @Override
+    public SharedState addPojos(ConfigItem item, SharedState relState, Console console) {
+        Objects.requireNonNull(dao,
+                translator.localize(LocaleResources.DAO_NOT_INITIALIZED).getContents());
+        ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId");
+        List<String> allAgents = procAgents.getAll();
+        long countBefore = getCount();
+        int totalItems = item.getNumber() * allAgents.size();
+        // populate network info records per agentID
+        console.getOutput().println("\n" + translator.localize(LocaleResources.POPULATING_RECORDS,
+                Integer.toString(totalItems), item.getName()).getContents());
+        int currVal = 0;
+        for (String agentId: allAgents) {
+            for (int i = 0; i < item.getNumber(); i++) {
+                NetworkInterfaceInfo info = new NetworkInterfaceInfo();
+                info.setAgentId(agentId);
+                String name = getRandomInterfaceName(i);
+                info.setInterfaceName(name);
+                info.setIp6Addr(getRandomIpv6Address(i, name));
+                info.setIp4Addr(getRandomIpv4Addrees(i));
+                dao.putNetworkInterfaceInfo(info);
+                currVal++;
+            }
+        }
+        reportSubmitted(item, currVal, console);
+        doWaitUntilCount(countBefore + totalItems, console, 200);
+        return relState;
+    }
+
+    private String getRandomIpv4Addrees(int i) {
+        int idx = getRandomInt(IPV4_FORMATS.length);
+        return String.format(IPV4_FORMATS[idx], getIpv4Octet(i));
+    }
+
+    private int getRandomInt(int upperBound) {
+        return (int)(Math.random() * upperBound);
+    }
+
+    private String getRandomIpv6Address(int i, String name) {
+        int idx = getRandomInt(IPV6_FORMATS.length);
+        return String.format(IPV6_FORMATS[idx], getIpv6Hextet(i), name);
+    }
+    
+    // package-private for testing
+    String getIpv6Hextet(int i) {
+        int remainder = i % IPv6Mod;
+        if (remainder == 0) {
+            // 0 isn't really an IP, make it 1 instead.
+            remainder = 1;
+        }
+        return Integer.toHexString(remainder);
+    }
+    
+    // package-private for testing
+    int getIpv4Octet(int i) {
+        int remainder = i % IPv4Mod;
+        if (remainder == 0) {
+            // 0 is network address, switch to IP
+            remainder = 1;
+        }
+        return remainder;
+    }
+
+    private String getRandomInterfaceName(int i) {
+        int idx = getRandomInt(IFACE_NAMES.length);
+        return IFACE_NAMES[idx] + i;
+    }
+
+    @Override
+    long getCount() {
+        return dao.getCount();
+    }
+
+    @Override
+    public String getHandledCollection() {
+        return NetworkInterfaceInfoDAO.networkInfoCategory.getName();
+    }
+
+    public void setDAO(NetworkInterfaceInfoDAO dao) {
+        this.dao = dao;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/ThreadPopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+
+import com.redhat.thermostat.common.Pair;
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.populator.internal.BasePopulator;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+import com.redhat.thermostat.storage.populator.internal.LocaleResources;
+import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
+import com.redhat.thermostat.thread.model.ThreadSession;
+import com.redhat.thermostat.thread.model.ThreadState;
+import com.redhat.thermostat.thread.model.ThreadSummary;
+import com.redhat.thermostat.thread.model.VmDeadLockData;
+
+public class ThreadPopulator extends BasePopulator {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    /**
+     * Package-private and static for testing.
+     */
+    static final int NUM_SAMPLES = 10;
+
+    public final String SESSION = "session";
+    private final int NUM_THREADS = 3;
+    private final long SEED = 5;
+    Random generator = new Random(SEED);
+    private static final String[] THREAD_NAMES = new String[] {
+            "Spencer", "Sheldon", "Alice", "Bob", "Julie", "Phoebe", "Alpha", "Beta", "Gamma",
+            "Theta", "Zeta",
+    };
+    static final String DEADLOCK_DESC_FORMAT = "" +
+            "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"%s\" Id=%d\n" +
+            "\tat sun.misc.Unsafe.park(Native Method)\n" +
+            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
+            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
+            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
+            "\t...\n\n" +
+            "\tNumber of locked synchronizers = 1\n" +
+            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" +
+            "\n\n" +
+            "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"%s\" Id=%d\n" +
+            "\tat sun.misc.Unsafe.park(Native Method)\n" +
+            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + 
+            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + 
+            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
+            "\t...\n\n" + 
+            "\tNumber of locked synchronizers = 1\n" +
+            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
+            "\n\n" +
+            "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"%s\" Id=%d\n" +
+            "\tat sun.misc.Unsafe.park(Native Method)\n" +
+            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" +
+            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + 
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + 
+            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
+            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + 
+            "\t...\n\n" +
+            "\tNumber of locked synchronizers = 1\n" +
+            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n";
+            
+    
+    private ThreadDao dao;
+
+    public ThreadPopulator() {
+        this(null);
+    }
+
+    public ThreadPopulator(ThreadDao dao) {
+        this.dao = dao;
+    }
+
+    @Override
+    public SharedState addPojos(ConfigItem item, SharedState relState, Console console) {
+        Objects.requireNonNull(dao,
+                translator.localize(LocaleResources.DAO_NOT_INITIALIZED).getContents());
+        // creates records per agent *and* vm
+        List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll();
+        List<String> vmIds = relState.getProcessedRecordsFor("vmId").getAll();
+        int perVmNumber = item.getNumber();
+        int totalCount = perVmNumber * agentIds.size() * vmIds.size();
+        int currCount = 0;
+        long countBefore = getCount();
+        console.getOutput().println("\n" +translator.localize(LocaleResources.POPULATING_RECORDS,
+                Integer.toString(totalCount), item.getName()).getContents());
+        long currTime = System.currentTimeMillis();
+        for (String agentId: agentIds) {
+            for (String vmId: vmIds) {
+                for (int i = 0; i < perVmNumber; i++) {
+                    ThreadSummary summary = new ThreadSummary();
+                    summary.setAgentId(agentId);
+                    summary.setVmId(vmId);
+                    int liveThreads = generator.nextInt(NUM_THREADS);
+                    summary.setCurrentLiveThreads(liveThreads);
+                    int daemonThreads = NUM_THREADS - liveThreads;
+                    summary.setCurrentDaemonThreads(daemonThreads);
+                    long timeStamp = currTime + i * 1000;
+                    summary.setTimeStamp(timeStamp);
+                    dao.saveSummary(summary);
+
+                    ThreadSession session = new ThreadSession();
+                    session.setSession(SESSION);
+                    session.setTimeStamp(timeStamp);
+                    session.setAgentId(agentId);
+                    session.setVmId(vmId);
+                    dao.saveSession(session);
+
+                    final Thread.State[] states = Thread.State.values();
+                    String state = states[generator.nextInt(states.length)].toString();
+                    String name = THREAD_NAMES[generator.nextInt(THREAD_NAMES.length)];
+
+                    for(int j = 0; j < NUM_SAMPLES; j++) {
+                        ThreadState threadState = new ThreadState();
+                        threadState.setTimeStamp(currTime + j * 1000);
+                        threadState.setVmId(vmId);
+                        threadState.setAgentId(agentId);
+                        threadState.setState(state);
+                        threadState.setId(i);
+                        threadState.setName(name);
+                        threadState.setSession(SESSION);
+                        dao.addThreadState(threadState);
+                    }
+
+                    ThreadHarvestingStatus status = new ThreadHarvestingStatus(agentId);
+                    status.setVmId(vmId);
+                    status.setTimeStamp(timeStamp);
+                    status.setHarvesting(generator.nextBoolean());
+                    dao.saveHarvestingStatus(status);
+
+                    VmDeadLockData data = new VmDeadLockData();
+                    data.setAgentId(agentId);
+                    data.setVmId(vmId);
+                    data.setTimeStamp(currTime + i * 10);
+                    data.setDeadLockDescription(getDeadlockedDescription(currCount));
+                    dao.saveDeadLockStatus(data);
+                    currCount++;
+                }
+            }
+        }
+        reportSubmitted(item, currCount, console);
+        doWaitUntilCount(countBefore + totalCount, console, 200);
+        return relState;
+    }
+
+    private String getDeadlockedDescription(int currCount) {
+        return String.format(DEADLOCK_DESC_FORMAT, getFormatStringArgs(currCount));
+    }
+
+    Object[] getFormatStringArgs(int currCount) {
+        List<Pair<String, Integer>> nameIdMapping = new ArrayList<>();
+        int[] randomIds = getIdValues(currCount, NUM_THREADS);
+        int randomEntry = getRandomInt(THREAD_NAMES.length);
+        for (int i = 0, idx; i < NUM_THREADS; i++) {
+            idx = (randomEntry + i) % THREAD_NAMES.length;
+            String name = THREAD_NAMES[idx];
+            int tid = randomIds[i];
+            nameIdMapping.add(new Pair<>(name, tid));
+        }
+        Object[] formatArgs = new Object[NUM_THREADS * 2 * 2];
+        formatArgs[0] = nameIdMapping.get(0).getFirst();
+        formatArgs[1] = nameIdMapping.get(0).getSecond();
+        for (int i = 2, j = 1; i < formatArgs.length - 2; i+= 4, j++) {
+            formatArgs[i] = nameIdMapping.get(j).getFirst();
+            formatArgs[i + 1] = nameIdMapping.get(j).getSecond();
+            formatArgs[i + 2] = nameIdMapping.get(j).getFirst();
+            formatArgs[i + 3] = nameIdMapping.get(j).getSecond();
+        }
+        formatArgs[formatArgs.length - 2] = nameIdMapping.get(0).getFirst();
+        formatArgs[formatArgs.length - 1] = nameIdMapping.get(0).getSecond();
+        return formatArgs;
+    }
+
+    private int getRandomInt(int len) {
+        return (int)(Math.random() * len);
+    }
+
+    private int[] getIdValues(int currCount, int length) {
+        int[] values = new int[length];
+        for (int i = 0; i < values.length; i++) {
+            values[i] = currCount + i;
+        }
+        return values;
+    }
+
+    @Override
+    long getCount() {
+        return dao.getDeadLockCount();
+    }
+
+    @Override
+    public String getHandledCollection() {
+        return ThreadDao.THREAD_HARVESTING_STATUS.getName();
+    }
+
+    public void setDAO(ThreadDao dao) {
+        this.dao = dao;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/VmInfoPopulator.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.storage.populator.internal.BasePopulator;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+import com.redhat.thermostat.storage.populator.internal.LocaleResources;
+
+public class VmInfoPopulator extends BasePopulator {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private VmInfoDAO dao;
+    
+    public VmInfoPopulator() {
+        this(null);
+    }
+    
+    public VmInfoPopulator(VmInfoDAO dao) {
+        this.dao = dao;
+    }
+
+    @Override
+    public SharedState addPojos(ConfigItem item, SharedState relState, Console console) {
+        Objects.requireNonNull(dao,
+                translator.localize(LocaleResources.DAO_NOT_INITIALIZED).getContents());
+        // Default to all alive, if unset
+        int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems();
+        ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId");
+        List<String> vmIds = new ArrayList<>();
+        List<String> allAgents = procAgents.getAll();
+        long countBefore = getCount();
+        int totalItems = item.getNumber() * allAgents.size();
+        // populate VM records per agentID
+        console.getOutput().println("\n" + translator.localize(LocaleResources.POPULATING_RECORDS,
+                Integer.toString(totalItems), item.getName()).getContents());
+        int currVal = 0;
+        for (String agentId: allAgents) {
+            for (int i = 0; i < item.getNumber(); i++) {
+                VmInfo info = new VmInfo();
+                info.setAgentId(agentId);
+                info.setJavaCommandLine("java DataPopulatorProducedVM --vm " + i  + " --version");
+                info.setJavaHome("/opt/foo/bar/java-1.8.0-openjdk/jre");
+                info.setJavaVersion("1.8.0");
+                info.setMainClass("com.redhat.thermostat.TestDataPopulator");
+                info.setLoadedNativeLibraries(new String[] { "glibc.so", "something.so" });
+                info.setProperties(getFakeJavaProperties(i, agentId));
+                StartStopTimeStamp ts = getFakeStartStopTimeStamp(i, aliveItems);
+                info.setStartTimeStamp(ts.startTS);
+                info.setStopTimeStamp(ts.stopTS);
+                info.setUsername("vm-user-" + i);
+                info.setUid(i);
+                info.setVmArguments("-XX:+UseG1Gc");
+                String vmId = UUID.randomUUID().toString();
+                info.setVmId(vmId);
+                vmIds.add(vmId);
+                info.setVmInfo("OpenJDK 8");
+                info.setVmPid(34 + i);
+                info.setVmVersion("hs 25");
+                info.setVmName("Hotspot");
+                dao.putVmInfo(info);
+                currVal++;
+            }
+        }
+        reportSubmitted(item, currVal, console);
+        doWaitUntilCount(countBefore + totalItems, console, 200);
+        relState.addProcessedRecords("vmId", new ProcessedRecords<>(vmIds));
+        return relState;
+    }
+    
+    private StartStopTimeStamp getFakeStartStopTimeStamp(int num, int aliveItems) {
+        long currTime = System.currentTimeMillis();
+        if (num < aliveItems) {
+            // create alive timestamp pair
+            long startTs = Long.MAX_VALUE;
+            long stopTs = currTime;
+            return new StartStopTimeStamp(startTs, stopTs);
+        }
+        // create dead timestamp pair
+        return new StartStopTimeStamp(currTime - (1000 + num), currTime - (500 + num));
+    }
+
+    private Map<String, String> getFakeJavaProperties(int i, String agentId) {
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("foo", "bar");
+        props.put("vm#", Integer.toString(i));
+        props.put("agentId", agentId);
+        return props;
+    }
+
+    @Override
+    long getCount() {
+        return dao.getCount();
+    }
+
+    @Override
+    public String getHandledCollection() {
+        return VmInfoDAO.vmInfoCategory.getName();
+    }
+    
+    private static class StartStopTimeStamp {
+        private final long startTS;
+        private final long stopTS;
+        
+        private StartStopTimeStamp(long start, long stop) {
+            this.startTS = start;
+            this.stopTS = stop;
+        }
+    }
+
+    public void setDAO(VmInfoDAO dao) {
+        this.dao = dao;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/ConfigItem.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config;
+
+public class ConfigItem {
+
+    public static final String NAME = "name";
+    public static final String NUMBER = "number";
+    public static final String ALIVE = "alive";
+    
+    public static final int UNSET = -1;
+    private final int number;
+    private final int aliveItems;
+    private final String name;
+    
+    public ConfigItem(int number, int aliveItems, String name) {
+        this.number = number;
+        this.aliveItems = aliveItems;
+        this.name = name;
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public int getAliveItems() {
+        return aliveItems;
+    }
+
+    public String getName() {
+        return name;
+    }
+    
+    @Override
+    public String toString() {
+        return name + " (" + number + "/" + aliveItems + ")";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfig.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.ConfigItemTypeAdapter;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.PopulationConfigTypeAdapterFactory;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.RelationShipTypeAdapter;
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+
+public class PopulationConfig {
+    
+    public static final String RECORDS = "records";
+    public static final String RELATIONSHIPS = "relationships";
+    private final Map<String, ConfigItem> configs;
+    private final List<ConfigItem> allConfigs;
+    private final Map<String, List<Relationship>> incomingRelationShips;
+    private final Map<String, List<Relationship>> outgoingRelationShips;
+    
+    private PopulationConfig() {
+        configs = new HashMap<>();
+        allConfigs = new ArrayList<>();
+        incomingRelationShips = new HashMap<>();
+        outgoingRelationShips = new HashMap<>();
+    }
+
+    public ConfigItem getConfig(String name) {
+        return configs.get(name);
+    }
+    
+    public List<ConfigItem> getConfigsTopologicallySorted() {
+        return topologicallySort(allConfigs);
+    }
+    
+    /**
+     * Sort config items topologically. That is, get them in an order so as
+     * to process collections with no incoming links to other collections.
+     * 
+     * It uses Kahn's algorithm to do so.
+     * 
+     * @param configs unsorted configs.
+     * @return A topologically sorted list.
+     */
+    private List<ConfigItem> topologicallySort(List<ConfigItem> configs) {
+        LinkedList<ConfigItem> sortedList = new LinkedList<>();
+        LinkedList<ConfigItem> queue = getConfigItemsWithNoIncomingEdge(configs);
+        while (!queue.isEmpty()) {
+            ConfigItem n = queue.remove(0);
+            sortedList.addLast(n);
+            List<Relationship> source = getOutgoingRelationShipsForConfig(n);
+            List<Relationship> outgoingRels = new LinkedList<>(source);
+            for (Relationship edge: outgoingRels) {
+                ConfigItem m = getConfig(edge.getTo());
+                removeEdge(edge, n, m);
+                if (hasNoIncomingEdge(m)) {
+                    queue.addLast(m);
+                }
+            }
+        }
+        if (hasRelationShips(configs)) {
+            throw new AssertionError("Relationships form at least one cycle! Excpected an acyclic directed graph.");
+        }
+        return sortedList;
+    }
+
+    private boolean hasRelationShips(List<ConfigItem> configs) {
+        for (ConfigItem i: configs) {
+            List<Relationship> incoming = getIncomingRelationShipsForConfig(i);
+            List<Relationship> outgoing = getOutgoingRelationShipsForConfig(i);
+            if (!incoming.isEmpty() ||
+                    !outgoing.isEmpty()) {
+                // We are going to bomb, print some debug info.
+                System.err.println("outgoings for " + i.getName() + " " + outgoing);
+                System.err.println("incomings for " + i.getName() + " " + incoming);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void removeEdge(Relationship toRemove, ConfigItem from, ConfigItem to) {
+        if (from == null || to == null) {
+            throw new InvalidConfigurationException("Found relationship [" +
+                                                    toRemove +
+                    "] but either incoming or outgoing records config is missing");
+        }
+        List<Relationship> incoming = getIncomingRelationShipsForConfig(to);
+        List<Relationship> outgoing = getOutgoingRelationShipsForConfig(from);
+        incoming.remove(toRemove);
+        outgoing.remove(toRemove);
+    }
+
+    private LinkedList<ConfigItem> getConfigItemsWithNoIncomingEdge(List<ConfigItem> allConfigs) {
+        LinkedList<ConfigItem> startNodes = new LinkedList<>();
+        for (ConfigItem item: allConfigs) {
+            if (hasNoIncomingEdge(item)) {
+                startNodes.add(item);
+            }
+        }
+        return startNodes;
+    }
+
+    private boolean hasNoIncomingEdge(ConfigItem item) {
+        List<Relationship> rels = getIncomingRelationShipsForConfig(item);
+        if (rels == null || rels.isEmpty()) {
+            return true;
+        }
+        return false;
+    }
+
+    private List<Relationship> getIncomingRelationShipsForConfig(ConfigItem item) {
+        List<Relationship> result = incomingRelationShips.get(item.getName());
+        if (result == null) {
+            return Collections.emptyList();
+        }
+        return result;
+    }
+    
+    private List<Relationship> getOutgoingRelationShipsForConfig(ConfigItem item) {
+        List<Relationship> result = outgoingRelationShips.get(item.getName());
+        if (result == null) {
+            return Collections.emptyList();
+        }
+        return result;
+    }
+    
+    private void addConfig(ConfigItem item) {
+        configs.put(item.getName(), item);
+        allConfigs.add(item);
+    }
+    
+    private void addIncomingRelationShipForConfig(ConfigItem item, Relationship relationship) {
+        addRelationShip(item, relationship, incomingRelationShips);
+    }
+    
+    private void addOutgoingRelationShipForConfig(ConfigItem item, Relationship relationship) {
+        addRelationShip(item, relationship, outgoingRelationShips);
+    }
+    
+    private void addRelationShip(ConfigItem item, Relationship relationship, Map<String, List<Relationship>> map) {
+        List<Relationship> existingRels = map.get(item.getName());
+        if (existingRels == null) {
+            existingRels = new LinkedList<>();
+            map.put(item.getName(), existingRels);
+        }
+        existingRels.add(relationship);
+    }
+    
+    public static PopulationConfig parseFromJsonString(String json) throws IOException {
+        Gson gson= new GsonBuilder()
+                        .registerTypeAdapter(ConfigItem.class, new ConfigItemTypeAdapter())
+                        .registerTypeAdapter(Relationship.class, new RelationShipTypeAdapter())
+                        .registerTypeAdapterFactory(new PopulationConfigTypeAdapterFactory())
+                        .create();
+        PopulationConfig pc = gson.fromJson(json, PopulationConfig.class);
+        return pc;
+    }
+    
+    public static PopulationConfig createFromLists(List<ConfigItem> items, List<Relationship> rels) {
+        PopulationConfig pc = new PopulationConfig();
+        for (ConfigItem item: items) {
+            pc.addConfig(item);
+            for (Relationship r: rels) {
+                // keep track of incoming relationships (incoming edge)
+                if (r.getTo().equals(item.getName())) {
+                    pc.addIncomingRelationShipForConfig(item, r);
+                }
+                // keep track of outgoing relationships (outgoing edge)
+                if (r.getFrom().equals(item.getName())) {
+                    pc.addOutgoingRelationShipForConfig(item, r);
+                }
+            }
+        }
+        return pc;
+    }
+    
+    @SuppressWarnings("serial")
+    static class InvalidConfigurationException extends RuntimeException {
+        
+        private InvalidConfigurationException(String msg) {
+            super(msg);
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/ConfigItemTypeAdapter.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+
+public class ConfigItemTypeAdapter extends TypeAdapter<ConfigItem> {
+
+    @Override
+    public ConfigItem read(JsonReader reader) throws IOException {
+        // handle null
+        if (reader.peek() == JsonToken.NULL) {
+            reader.nextNull();
+            return null;
+        }
+        
+        reader.beginObject();
+        ConfigItem item = parseConfigItem(reader);
+        reader.endObject();
+        
+        return item;
+    }
+
+    private ConfigItem parseConfigItem(JsonReader reader) throws IOException {
+        Map<String, Object> values = new HashMap<>();
+        while (reader.hasNext()) {
+            String name = reader.nextName();
+            switch(name) {
+            case ConfigItem.NAME:
+                values.put(ConfigItem.NAME, reader.nextString());
+                break;
+            case ConfigItem.ALIVE:
+                values.put(ConfigItem.ALIVE, reader.nextInt());
+                break;
+            case ConfigItem.NUMBER:
+                values.put(ConfigItem.NUMBER, reader.nextInt());
+                break;
+            default:
+                throw new IllegalStateException("Unknown config value: '" + name + "'");
+            }
+        }
+        String collName = (String)values.get(ConfigItem.NAME);
+        String collectionDetails = collName == null ? "" : "[" + collName + "] ";
+        Integer number = (Integer)values.get(ConfigItem.NUMBER);
+        Integer aliveItems = (Integer)values.get(ConfigItem.ALIVE);
+        int aliveItemsForSanityTest = getAliveCount(aliveItems);
+        if (number < 0 || aliveItemsForSanityTest < 0) {
+            throw new IllegalArgumentException(collectionDetails + "number of items and alive items must be positive");
+        }
+        if (number - aliveItemsForSanityTest < 0) {
+            throw new IllegalArgumentException(collectionDetails + "alive items > number of total items.");
+        }
+        return new ConfigItem(getValue(number), getValue(aliveItems), collName);
+    }
+
+    private int getAliveCount(Integer aliveItems) {
+        if (aliveItems != null) {
+            return aliveItems;
+        }
+        return 0; // return 0 for unset, just so that we make sanity checks happy
+    }
+
+    private int getValue(Integer value) {
+        return value == null ? ConfigItem.UNSET : value;
+    }
+
+    @Override
+    public void write(JsonWriter writer, ConfigItem item) throws IOException {
+        throw new NotImplementedException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/NotImplementedException.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+@SuppressWarnings("serial")
+class NotImplementedException extends RuntimeException {
+    // nothing
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapter.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig;
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+
+public class PopulationConfigTypeAdapter extends TypeAdapter<PopulationConfig> {
+    
+    private final Gson gson;
+    
+    public PopulationConfigTypeAdapter(Gson gson) {
+        this.gson = gson;
+    }
+
+    @Override
+    public void write(JsonWriter out, PopulationConfig config) throws IOException {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public PopulationConfig read(JsonReader in) throws IOException {
+        // handle null
+        if (in.peek() == JsonToken.NULL) {
+            in.nextNull();
+            return null;
+        }
+        in.beginObject();
+        PopulationConfig config = parsePopulationConfig(in);
+        in.endObject();
+        return config;
+    }
+
+    private PopulationConfig parsePopulationConfig(JsonReader in) throws IOException {
+        Map<String, Object> values = new HashMap<>();
+        while (in.hasNext()) {
+            String name = in.nextName();
+            switch(name) {
+            case PopulationConfig.RECORDS:
+                values.put(PopulationConfig.RECORDS, parseRecords(in));
+                break;
+            case PopulationConfig.RELATIONSHIPS:
+                values.put(PopulationConfig.RELATIONSHIPS, parseRelationships(in));
+                break;
+            default:
+                throw new IllegalStateException("Unknown population config value: '" + name + "'");
+            }
+        }
+        ConfigItem[] rawItems = (ConfigItem[])values.get(PopulationConfig.RECORDS);
+        Relationship[] rawRels = (Relationship[])values.get(PopulationConfig.RELATIONSHIPS);
+        List<Relationship> rels;
+        if (rawRels == null) {
+            rels = Collections.emptyList();
+        } else {
+            rels = Arrays.asList(rawRels);
+        }
+        return PopulationConfig.createFromLists(Arrays.asList(rawItems), rels);
+    }
+
+    private Relationship[] parseRelationships(JsonReader in) {
+        return gson.fromJson(in, Relationship[].class);
+    }
+
+    private ConfigItem[] parseRecords(JsonReader in) throws IOException {
+        return gson.fromJson(in, ConfigItem[].class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapterFactory.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig;
+
+public class PopulationConfigTypeAdapterFactory implements TypeAdapterFactory {
+
+    @Override
+    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
+        Class<?> rawType = type.getRawType();
+        if (rawType == PopulationConfig.class) {
+            @SuppressWarnings("unchecked")
+            TypeAdapter<T> ta = (TypeAdapter<T>)new PopulationConfigTypeAdapter(gson);
+            return ta;
+        }
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapter.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+
+public class RelationShipTypeAdapter extends TypeAdapter<Relationship> {
+
+    @Override
+    public Relationship read(JsonReader in) throws IOException {
+        // handle null
+        if (in.peek() == JsonToken.NULL) {
+            in.nextNull();
+            return null;
+        }
+        
+        in.beginObject();
+        Relationship rel = parseRelationShip(in);
+        in.endObject();
+        
+        return rel;
+    }
+
+    private Relationship parseRelationShip(JsonReader in) throws IOException {
+        Map<String, String> values = new HashMap<>();
+        while (in.hasNext()) {
+            String name = in.nextName();
+            switch(name) {
+            case Relationship.FROM:
+                values.put(Relationship.FROM, in.nextString());
+                break;
+            case Relationship.TO:
+                values.put(Relationship.TO, in.nextString());
+                break;
+            case Relationship.KEY:
+                values.put(Relationship.KEY, in.nextString());
+                break;
+            default:
+                throw new IllegalStateException("Unknown relationship value: '" + name + "'");
+            }
+        }
+        return new Relationship(values.get(Relationship.FROM), values.get(Relationship.TO), values.get(Relationship.KEY));
+    }
+
+    @Override
+    public void write(JsonWriter out, Relationship relationship) throws IOException {
+        throw new NotImplementedException();
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/ProcessedRecords.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.dependencies;
+
+import java.util.List;
+
+/**
+ *
+ * @param <T> The underlying type of the key
+ */
+public class ProcessedRecords<T> {
+
+    private final List<T> allRecords;
+    
+    public ProcessedRecords(List<T> allRecords) {
+        this.allRecords = allRecords;
+    }
+    
+    public List<T> getAll() {
+        return allRecords;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/Relationship.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.dependencies;
+
+import java.util.Objects;
+
+public class Relationship {
+
+    public static final String TO = "to";
+    public static final String FROM = "from";
+    public static final String KEY = "key";
+    private final String from;
+    private final String to;
+    private final String key;
+    
+    public Relationship(String from, String to, String key) {
+        this.from = from;
+        this.to = to;
+        this.key = key;
+    }
+
+    public String getFrom() {
+        return from;
+    }
+
+    public String getTo() {
+        return to;
+    }
+
+    public String getKey() {
+        return key;
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || o.getClass() != Relationship.class) {
+            return false;
+        }
+        Relationship other = (Relationship)o;
+        return Objects.equals(to, other.to) &&
+                Objects.equals(from, other.from) &&
+                Objects.equals(key, other.key);
+    }
+    
+    @Override
+    public int hashCode() {
+        return Objects.hash(to, from, key);
+    }
+    
+    @Override
+    public String toString() {
+        return from + " -> " + to + "(" + key + ")";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/SharedState.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.dependencies;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SharedState {
+    
+    private final Map<Object, ProcessedRecords<?>> processedRecs;
+    private final Map<String, Object> props;
+    
+    public SharedState() {
+        processedRecs = new HashMap<>();
+        props = new HashMap<>();
+    }
+
+    public <T> ProcessedRecords<T> getProcessedRecordsFor(T key) {
+        @SuppressWarnings("unchecked")
+        ProcessedRecords<T> item = (ProcessedRecords<T>)processedRecs.get(key);
+        return item;
+    }
+    
+    public <T> void addProcessedRecords(T key, ProcessedRecords<T> recs) {
+        processedRecs.put(key, recs);
+    }
+    
+    public void addProperty(String key, Object value) {
+        props.put(key, value);
+    }
+    
+    public Object getProperty(String key) {
+        return props.get(key);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.CategoryRegistration	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,1 @@
+com.redhat.thermostat.storage.profile.internal.StorageProfileCommand
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,1 @@
+com.redhat.thermostat.storage.profile.internal.StorageProfileCommand
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/main/resources/com/redhat/thermostat/storage/populator/command/locale/strings.properties	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,14 @@
+COMMON_PATHS_SERVICE_UNAVAILABLE = Unable to get CommonPaths service.
+HOST_SERVICE_UNAVAILABLE = Unable to get HostInfoDAO service.
+AGENT_SERVICE_UNAVAILABLE = Unable to get AgentInfoDAO service.
+VM_SERVICE_UNAVAILABLE = Unable to get VmInfoDAO service.
+NETWORK_SERVICE_UNAVAILABLE = Unable to get NetworkInterfaceInfoDAO service.
+THREAD_SERVICE_UNAVAILABLE = Unable to get ThreadDao service.
+DAO_NOT_INITIALIZED = DAO must be initialized to populate.
+WAITING_FOR_ARRIVAL = Waiting for storage items to arrive at backend...
+ITEMS_HAVE_ARRIVED = Items have arrived.
+POPULATING_RECORDS = Populating {0} {1} records...
+RECORDS_SUBMITTED = Submitted {0} {1} records to storage.
+NONEXISTENT_CONFIG = Config file "{0}" does not exist!
+CONFIG_PARSING_FAILED = Failed to parse config file.
+NO_POPULATOR_FOUND = No populator for collection "{0}" found.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/StoragePopulatorCommandTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.dao.HostInfoDAO;
+import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.model.AgentInformation;
+import com.redhat.thermostat.storage.model.HostInfo;
+import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.VmDeadLockData;
+
+public class StoragePopulatorCommandTest {
+
+    private static final String SOME_CONFIG = "config";
+
+    private StoragePopulatorCommand command;
+    private CommandContext ctx;
+    private Arguments args;
+
+    CommonPaths paths;
+    HostInfoDAO hostInfoDAO;
+    AgentInfoDAO agentInfoDAO;
+    VmInfoDAO vmInfoDAO;
+    NetworkInterfaceInfoDAO networkInfoDAO;
+    ThreadDao threadDao;
+
+    private ByteArrayOutputStream outputBAOS, errorBAOS;
+    private PrintStream output, error;
+    private Console console;
+
+    @Before
+    public void setUp() {
+        ctx = mock(CommandContext.class);
+        args = mock(Arguments.class);
+
+        console = mock(Console.class);
+
+        outputBAOS = new ByteArrayOutputStream();
+        output = new PrintStream(outputBAOS);
+
+        errorBAOS = new ByteArrayOutputStream();
+        error = new PrintStream(errorBAOS);
+
+        when(ctx.getArguments()).thenReturn(args);
+        when(ctx.getConsole()).thenReturn(console);
+        when(console.getError()).thenReturn(error);
+        when(console.getOutput()).thenReturn(output);
+    }
+
+    @Test
+    public void testCommandFailsWhenDependenciesUnavailable() {
+        command = new StoragePopulatorCommand();
+        command.setServicesUnavailable();
+
+        try {
+            command.run(ctx);
+            fail("A CommandException was expected but not thrown.");
+        } catch (CommandException e) {
+            assertTrue(e.getMessage().matches("Unable to get .* service\\."));
+        }
+    }
+
+    @Test
+    public void testCommandFailsWithNonexistentConfig() throws CommandException {
+        final File nonexistentConfig = mock(File.class);
+        when(nonexistentConfig.exists()).thenReturn(false);
+        when(nonexistentConfig.getAbsolutePath()).thenReturn("/foo/bar/" + SOME_CONFIG);
+        command = new StoragePopulatorCommand() {
+            @Override
+            File getConfigFile(Arguments args) {
+                return nonexistentConfig;
+            }
+        };
+        setUpServices();
+
+        command.run(ctx);
+        String errorString = new String(errorBAOS.toByteArray());
+        assertEquals("Config file \"/foo/bar/config\" does not exist!\n", errorString);
+    }
+
+    @Test
+    public void testCommandFailsWithInvalidConfig() throws CommandException, IOException {
+        final File invalidConfig = mock(File.class);
+        when(invalidConfig.exists()).thenReturn(true);
+        when(invalidConfig.toPath()).thenThrow(IOException.class);
+
+        command = new StoragePopulatorCommand() {
+            @Override
+            File getConfigFile(Arguments args) {
+                return invalidConfig;
+            }
+        };
+        setUpServices();
+
+        command.run(ctx);
+        String errorString = new String(errorBAOS.toByteArray());
+        assertEquals("Failed to parse config file.\n", errorString);
+    }
+
+    @Test
+    public void testCommandFailsWithInvalidPopulator() throws CommandException {
+        final File invalidConfigFile = new File(
+                getClass().getResource("/invalid-config.json").getFile());
+        command = new StoragePopulatorCommand() {
+            @Override
+            File getConfigFile(Arguments args) {
+                return invalidConfigFile;
+            }
+        };
+        setUpServices();
+
+        command.run(ctx);
+        String errorString = new String(errorBAOS.toByteArray());
+        assertEquals("No populator for collection \"foo\" found.\n", errorString);
+    }
+
+    @Test
+    public void testCommandPopulatesDatabase() throws CommandException {
+        final File validConfigFile = new File(
+                getClass().getResource("/valid-config.json").getFile());
+        command = new StoragePopulatorCommand() {
+            @Override
+            File getConfigFile(Arguments args) {
+                return validConfigFile;
+            }
+        };
+
+        setUpServices();
+
+        // the following counts are dependent on the parameters in valid-config.json
+        int agentCount = 2;
+        int hostCount = 2;
+        int networkCount = 40;
+        int deadLockCount = 100;
+        int vmCount = 10;
+
+        when(agentInfoDAO.getCount()).thenReturn(0l).thenReturn((long) agentCount);
+        when(hostInfoDAO.getCount()).thenReturn(0l).thenReturn((long) hostCount);
+        when(networkInfoDAO.getCount()).thenReturn(0l).thenReturn((long) networkCount);
+        when(threadDao.getDeadLockCount()).thenReturn(0l).thenReturn((long) deadLockCount);
+        when(vmInfoDAO.getCount()).thenReturn(0l).thenReturn((long) vmCount);
+
+        command.run(ctx);
+
+        verify(agentInfoDAO, times(agentCount)).addAgentInformation(any(AgentInformation.class));
+        verify(hostInfoDAO, times(hostCount)).putHostInfo(any(HostInfo.class));
+        verify(networkInfoDAO, times(networkCount)).putNetworkInterfaceInfo(
+                any(NetworkInterfaceInfo.class));
+        verify(threadDao, times(deadLockCount)).saveDeadLockStatus(any(VmDeadLockData.class));
+        verify(vmInfoDAO, times(vmCount)).putVmInfo(any(VmInfo.class));
+    }
+
+    private void setUpServices () {
+        paths = mock(CommonPaths.class);
+        command.setPaths(paths);
+        hostInfoDAO = mock(HostInfoDAO.class);
+        command.setHostInfoDAO(hostInfoDAO);
+        agentInfoDAO = mock(AgentInfoDAO.class);
+        command.setAgentInfoDAO(agentInfoDAO);
+        vmInfoDAO = mock(VmInfoDAO.class);
+        command.setVmInfoDAO(vmInfoDAO);
+        networkInfoDAO = mock(NetworkInterfaceInfoDAO.class);
+        command.setNetworkInfoDAO(networkInfoDAO);
+        threadDao = mock(ThreadDao.class);
+        command.setThreadDao(threadDao);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/ActivatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.populator.StoragePopulatorCommand;
+import com.redhat.thermostat.storage.populator.internal.Activator;
+import com.redhat.thermostat.testutils.StubBundleContext;
+
+public class ActivatorTest {
+    @Test
+    public void verifyActivatorRegistersServices() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        Activator activator = new Activator();
+
+        activator.start(ctx);
+        assertCommandIsRegistered(ctx, "storage-populator", StoragePopulatorCommand.class);
+        activator.stop(ctx);
+
+        assertEquals(0, ctx.getServiceListeners().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/AgentInfoPopulatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.model.AgentInformation;
+import com.redhat.thermostat.storage.populator.internal.AgentInfoPopulator;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class AgentInfoPopulatorTest {
+
+    @Test
+    public void canHandleAgentInfoCollection() {
+        AgentInfoPopulator putter = new AgentInfoPopulator();
+        assertEquals("agent-config", putter.getHandledCollection());
+    }
+    
+    @Test
+    public void canAddPojos() {
+        int totalRecords = 23;
+        AgentInfoDAO dao = mock(AgentInfoDAO.class);
+        // Initially return 0, then return the expected count
+        when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
+        AgentInfoPopulator putter = new AgentInfoPopulator(dao);
+        ConfigItem item = new ConfigItem(totalRecords, 3, "agent-config");
+        SharedState state = new SharedState();
+        Console console = mock(Console.class);
+        PrintStream ps = mock(PrintStream.class);
+        when(console.getOutput()).thenReturn(ps);
+        state = putter.addPojos(item, state, console);
+        ArgumentCaptor<AgentInformation> agentInfoCaptor = ArgumentCaptor.forClass(AgentInformation.class);
+        verify(dao, times(23)).addAgentInformation(agentInfoCaptor.capture());
+        List<AgentInformation> agentInfos = agentInfoCaptor.getAllValues();
+        List<AgentInformation> filtered = getAliveAgentInfos(agentInfos);
+        assertEquals(3, filtered.size());
+        ProcessedRecords<String> recs = state.getProcessedRecordsFor("agentId");
+        assertEquals(23, recs.getAll().size());
+        ProcessedRecords<String> notExisting = state.getProcessedRecordsFor("foo-bar");
+        assertNull(notExisting);
+    }
+
+    private List<AgentInformation> getAliveAgentInfos(List<AgentInformation> agentInfos) {
+        List<AgentInformation> aliveInfos = new ArrayList<>();
+        for (AgentInformation info: agentInfos) {
+            if (info.isAlive()) {
+                aliveInfos.add(info);
+            }
+        }
+        return aliveInfos;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/BasePopulatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class BasePopulatorTest {
+
+    private BasePopulator populator;
+
+    private ByteArrayOutputStream outputBAOS;
+    private PrintStream output;
+    private Console console;
+
+    @Before
+    public void setUp() {
+        populator = createBasePopulatorForTest();
+
+        console = mock(Console.class);
+        outputBAOS = new ByteArrayOutputStream();
+        output = new PrintStream(outputBAOS);
+        when(console.getOutput()).thenReturn(output);
+    }
+
+    private BasePopulator createBasePopulatorForTest() {
+        return new BasePopulator() {
+            private int currCount = 0;
+
+            @Override
+            long getCount() {
+                currCount++;
+                return currCount;
+            }
+
+            @Override
+            public SharedState addPojos(ConfigItem item, SharedState relState, Console console) {
+                return null;
+            }
+
+            @Override
+            public String getHandledCollection() {
+                return null;
+            }
+        };
+    }
+
+    @Test
+    public void testDoWaitUntilCount() {
+        final long expectedCount = 3;
+
+        populator.doWaitUntilCount(expectedCount, console, 0);
+
+        String expected = "Waiting for storage items to arrive at backend...";
+        for (int i = 0; i < (expectedCount - 1); i++) {
+            expected = expected + ".";
+        }
+        expected = expected + "Items have arrived.\n";
+
+        String outputString = new String(outputBAOS.toByteArray());
+        assertEquals(expected, outputString);
+    }
+
+    @Test
+    public void testReportSubmitted() {
+        final String name  = "foo";
+        final int totalCount = 3;
+
+        ConfigItem item = mock(ConfigItem.class);
+        when(item.getName()).thenReturn(name);
+
+        populator.reportSubmitted(item, totalCount, console);
+
+        String expectedString  = "Submitted " + totalCount + " " + name + " records to storage.\n";
+        String outputString = new String(outputBAOS.toByteArray());
+        assertEquals(expectedString, outputString);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/HostInfoPopulatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.dao.HostInfoDAO;
+import com.redhat.thermostat.storage.model.HostInfo;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class HostInfoPopulatorTest {
+
+    @Test
+    public void handlesCorrectCollection() {
+        HostInfoPopulator populator = new HostInfoPopulator();
+        assertEquals("host-info", populator.getHandledCollection());
+    }
+    
+    @Test
+    public void canPopulateToStorage() {
+        String[] agents = new String[] {
+                "host-agent1", "host-agent2", "host-agent3", "host-agent4"
+        };
+        List<String> agentIds = Arrays.asList(agents);
+        SharedState state = mock(SharedState.class);
+        @SuppressWarnings("unchecked")
+        ProcessedRecords<String> procRecs = mock(ProcessedRecords.class);
+        when(procRecs.getAll()).thenReturn(agentIds);
+        when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs);
+        int totalRecords = agents.length;
+        HostInfoDAO dao = mock(HostInfoDAO.class);
+        // Initially return 0, then return the expected count
+        when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
+        
+        ConfigItem config = new ConfigItem(1, ConfigItem.UNSET, "host-info");
+        HostInfoPopulator populator = new HostInfoPopulator(dao);
+        Console console = mock(Console.class);
+        PrintStream ps = mock(PrintStream.class);
+        when(console.getOutput()).thenReturn(ps);
+        populator.addPojos(config, state, console);
+        ArgumentCaptor<HostInfo> captor = ArgumentCaptor.forClass(HostInfo.class);
+        verify(dao, times(totalRecords)).putHostInfo(captor.capture());
+        List<HostInfo> values = captor.getAllValues();
+        // ensure no memory values are negative
+        for (HostInfo info: values) {
+            if (info.getTotalMemory() < 0) {
+                throw new AssertionError("Invalid memory value: " + info.getTotalMemory() + " < 0");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/NetworkInfoPopulatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
+import com.redhat.thermostat.storage.populator.internal.NetworkInfoPopulator;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class NetworkInfoPopulatorTest {
+
+    @Test
+    public void canHandleCorrectCollection() {
+        NetworkInfoPopulator populator = new NetworkInfoPopulator();
+        assertEquals("network-info", populator.getHandledCollection());
+    }
+    
+    @Test
+    public void testPopulation() {
+        NetworkInterfaceInfoDAO dao = mock(NetworkInterfaceInfoDAO.class);
+        NetworkInfoPopulator populator = new NetworkInfoPopulator(dao);
+        
+        String[] agentIds = new String[] {
+                "testAgent1", "testAgent2", "testAgent3", "testAgent4"
+        };
+        int perAgentItems = 100;
+        int totalRecords = perAgentItems * agentIds.length;
+        when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
+        List<String> agents = Arrays.asList(agentIds);
+        SharedState state = new SharedState();
+        state.addProcessedRecords("agentId", new ProcessedRecords<>(agents));
+        ConfigItem config = new ConfigItem(perAgentItems, ConfigItem.UNSET, "network-info");
+        Console console = mock(Console.class);
+        PrintStream ps = mock(PrintStream.class);
+        when(console.getOutput()).thenReturn(ps);
+        populator.addPojos(config, state, console);
+        ArgumentCaptor<NetworkInterfaceInfo> captor = ArgumentCaptor.forClass(NetworkInterfaceInfo.class);
+        verify(dao, times(totalRecords)).putNetworkInterfaceInfo(captor.capture());
+        List<NetworkInterfaceInfo> list = captor.getAllValues();
+        // expected agentId + iface name to be unique (since REPLACE otherwise replaces some random values)
+        Set<String> uniqueSet = new HashSet<>();
+        for (NetworkInterfaceInfo info: list) {
+            String agentId = info.getAgentId();
+            String ifaceName = info.getInterfaceName();
+            String key = agentId + ifaceName;
+            if (uniqueSet.contains(key)) {
+                throw new AssertionError("Expected interface names to be unique per agent");
+            } else {
+                uniqueSet.add(key);
+            }
+        }
+    }
+    
+    @Test
+    public void iPv6HextetRollOver() {
+        String ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("fffe", 16));
+        assertEquals("fffe", ipv6);
+        ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("ffff", 16));
+        assertEquals("1", ipv6);
+        ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("eee1", 16));
+        assertEquals("eee1", ipv6);
+    }
+    
+    @Test
+    public void iPv4OctetsRollOver() {
+        int octet = new NetworkInfoPopulator().getIpv4Octet(255);
+        assertEquals(1, octet);
+        octet = new NetworkInfoPopulator().getIpv4Octet(256);
+        assertEquals(1, octet);
+        octet = new NetworkInfoPopulator().getIpv4Octet(114);
+        assertEquals(114, octet);
+    }
+    
+    @Test
+    public void stringFormatIpv6Template() {
+        String formattedString = String.format(NetworkInfoPopulator.IPV6_FORMATS[1], "ff", "scope");
+        assertEquals("fe80::56ee:75ff:fe35:ff%scope", formattedString);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/ThreadPopulatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.model.BasePojo;
+import com.redhat.thermostat.storage.populator.internal.ThreadPopulator;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+import com.redhat.thermostat.thread.dao.ThreadDao;
+import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
+import com.redhat.thermostat.thread.model.ThreadSession;
+import com.redhat.thermostat.thread.model.ThreadState;
+import com.redhat.thermostat.thread.model.ThreadSummary;
+import com.redhat.thermostat.thread.model.VmDeadLockData;
+
+public class ThreadPopulatorTest {
+    
+    private static final String EXPECTED_DESCRIPTION = "" +
+            "\"Mallory\" Id=12 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"Alice\" Id=10\n" +
+            "\tat sun.misc.Unsafe.park(Native Method)\n" +
+            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
+            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
+            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
+            "\t...\n\n" +
+            "\tNumber of locked synchronizers = 1\n" +
+            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2" +
+            "\n\n\n" +
+            "\"Alice\" Id=10 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"Bob\" Id=11\n" +
+            "\tat sun.misc.Unsafe.park(Native Method)\n" +
+            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + 
+            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + 
+            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" +
+            "\t...\n\n" + 
+            "\tNumber of locked synchronizers = 1\n" +
+            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" +
+            "\n\n" +
+            "\"Bob\" Id=11 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"Mallory\" Id=12\n" +
+            "\tat sun.misc.Unsafe.park(Native Method)\n" +
+            "\t-  waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" +
+            "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + 
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" +
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + 
+            "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + 
+            "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" +
+            "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" +
+            "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + 
+            "\t...\n\n" +
+            "\tNumber of locked synchronizers = 1\n" +
+            "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n";
+
+    private static final String[] AGENTS = new String[] {
+            "fooAgent1", "fooBarAgent", "testAgent", "someAgent"
+    };
+    private static final String[] VMS = new String[] {
+            "vm1", "vm2", "vm3", "vm4", "vm5"
+    };
+
+    private ThreadDao dao;
+    
+    @Test
+    public void testFormatDeadlockDesc() {
+        Object[] stringFormatArgs = new Object[] {
+                "Mallory", 12,
+                "Alice", 10,
+                "Alice", 10,
+                "Bob", 11,
+                "Bob", 11,
+                "Mallory", 12
+        };
+        assertEquals(EXPECTED_DESCRIPTION, String.format(ThreadPopulator.DEADLOCK_DESC_FORMAT, stringFormatArgs));
+    }
+    
+    @Test
+    public void canGetRandomThreadNames() {
+        Object[] args = new ThreadPopulator().getFormatStringArgs(2);
+        assertEquals(12, args.length);
+        Map<Integer, Integer> tids = new HashMap<>();
+        Map<String, Integer> threadNames = new HashMap<>();
+        for (int i = 0; i < args.length; i +=2) {
+            Object arg1 = args[i];
+            Object arg2 = args[i + 1];
+            assertEquals(String.class, arg1.getClass());
+            assertEquals(Integer.class, arg2.getClass());
+            if (tids.containsKey(arg2)) {
+                Integer value = tids.get(arg2);
+                value += 1;
+                tids.put((Integer)arg2, value);
+            } else {
+                tids.put((Integer)arg2, 1);
+            }
+            if (threadNames.containsKey(arg1)) {
+                Integer value = threadNames.get(arg1);
+                value += 1;
+                threadNames.put((String)arg1, value);
+            } else {
+                threadNames.put((String)arg1, 1);
+            }
+        }
+        for (String key : threadNames.keySet()) {
+            int value = threadNames.get(key);
+            assertEquals(2, value);
+        }
+        for (Integer key : tids.keySet()) {
+            int value = tids.get(key);
+            assertEquals(2, value);
+        }
+    }
+
+    @Test
+    public void canHandleAppropriateCollection() {
+        ThreadPopulator populator = new ThreadPopulator();
+        assertEquals("vm-thread-harvesting", populator.getHandledCollection());
+    }
+
+    @Test
+    public void canAddThreadData() {
+        int perVmCount = 123;
+        int totalCount = perVmCount * AGENTS.length * VMS.length;
+        setUp(perVmCount, totalCount);
+
+        assertThreadSummaries(totalCount, perVmCount);
+        assertThreadSessions(totalCount, perVmCount);
+        assertThreadStates(totalCount, perVmCount);
+        assertThreadHarvestingStatus(totalCount, perVmCount);
+        assertDeadlockInfo(perVmCount, totalCount);
+    }
+
+    private void setUp(int perVmCount, int totalCount) {
+        ConfigItem config = new ConfigItem(perVmCount, ConfigItem.UNSET, "vm-deadlock-data");
+        dao = mock(ThreadDao.class);
+        when(dao.getDeadLockCount()).thenReturn(0L).thenReturn((long)totalCount);
+        ThreadPopulator populator = new ThreadPopulator(dao);
+        SharedState state = mock(SharedState.class);
+        when(state.getProcessedRecordsFor("agentId")).thenReturn(new ProcessedRecords<>(Arrays.asList(AGENTS)));
+        when(state.getProcessedRecordsFor("vmId")).thenReturn(new ProcessedRecords<>(Arrays.asList(VMS)));
+        Console console = mock(Console.class);
+        PrintStream ps = mock(PrintStream.class);
+        when(console.getOutput()).thenReturn(ps);
+        SharedState retval = populator.addPojos(config, state, console);
+        assertSame(retval, state);
+    }
+
+    private void assertThreadSummaries(int totalCount, int perVmCount) {
+        ArgumentCaptor<ThreadSummary> summaryCaptor = ArgumentCaptor.forClass(ThreadSummary.class);
+        verify(dao, times(totalCount)).saveSummary(summaryCaptor.capture());
+        List<ThreadSummary> savedValues = summaryCaptor.getAllValues();
+        assertEquals(totalCount, savedValues.size());
+        checkInstances(savedValues, VMS.length * perVmCount);
+    }
+
+    private void assertThreadSessions(int totalCount, int perVmCount) {
+        ArgumentCaptor<ThreadSession> sessionCaptor = ArgumentCaptor.forClass(ThreadSession.class);
+        verify(dao, times(totalCount)).saveSession(sessionCaptor.capture());
+        List<ThreadSession> savedValues = sessionCaptor.getAllValues();
+        assertEquals(totalCount, savedValues.size());
+        checkInstances(savedValues, VMS.length * perVmCount);
+    }
+
+    private void assertThreadStates(int totalCount, int perVmCount) {
+        ArgumentCaptor<ThreadState> stateCaptor = ArgumentCaptor.forClass(ThreadState.class);
+        verify(dao, times(totalCount * ThreadPopulator.NUM_SAMPLES)).
+                addThreadState(stateCaptor.capture());
+        List<ThreadState> savedValues = stateCaptor.getAllValues();
+        assertEquals(totalCount * ThreadPopulator.NUM_SAMPLES, savedValues.size());
+        checkInstances(savedValues, VMS.length * perVmCount * ThreadPopulator.NUM_SAMPLES);
+    }
+
+    private void assertThreadHarvestingStatus(int totalCount, int perVmCount) {
+        ArgumentCaptor<ThreadHarvestingStatus> statusCaptor =
+                ArgumentCaptor.forClass(ThreadHarvestingStatus.class);
+        verify(dao, times(totalCount)).saveHarvestingStatus(statusCaptor.capture());
+        List<ThreadHarvestingStatus> savedValues = statusCaptor.getAllValues();
+        checkInstances(savedValues, VMS.length * perVmCount);
+    }
+
+    private void checkInstances(List<? extends BasePojo> savedValues, int expected) {
+        List<String> agentIds = new ArrayList<>();
+        for (int i = 0; i < savedValues.size(); i++) {
+            agentIds.add(savedValues.get(i).getAgentId());
+        }
+
+        for (String agentId : AGENTS) {
+            int numInstances = Collections.frequency(agentIds, agentId);
+            assertEquals(expected, numInstances);
+        }
+    }
+
+    private void assertDeadlockInfo(int perVmCount, int totalCount) {
+        ArgumentCaptor<VmDeadLockData> deadlockInfoCaptor = ArgumentCaptor.forClass(VmDeadLockData.class);
+        verify(dao, times(totalCount)).saveDeadLockStatus(deadlockInfoCaptor.capture());
+        List<VmDeadLockData> savedValues = deadlockInfoCaptor.getAllValues();
+        assertEquals(totalCount, savedValues.size());
+        List<VmDeadLockData> perVmIdAgentDeadlockData = getFilteredByVmId(savedValues, "vm3");
+        assertEquals(perVmCount * AGENTS.length, perVmIdAgentDeadlockData.size());
+        List<VmDeadLockData> perAgentIdDeadlockData = getFilteredByAgentId(savedValues, "fooAgent1");
+        verifyVmIdsDifferent(perAgentIdDeadlockData);
+    }
+
+    private List<VmDeadLockData> getFilteredByAgentId(List<VmDeadLockData> perVmDeadlockData, String agentId) {
+        List<VmDeadLockData> filteredValues = new ArrayList<>();
+        for (VmDeadLockData data: perVmDeadlockData) {
+            if (data.getAgentId().equals(agentId)) {
+                filteredValues.add(data);
+            }
+        }
+        return filteredValues;
+    }
+
+    private void verifyVmIdsDifferent(List<VmDeadLockData> perVmDeadlockData) {
+        Set<String> vmIds = new HashSet<>();
+        for (VmDeadLockData data: perVmDeadlockData) {
+            if (vmIds.contains(data.getVmId())) {
+                throw new AssertionError("Duplicate VM ID per agent. Duplicate was: " + data.getVmId());
+            }
+            vmIds.add(data.getAgentId());
+        }
+    }
+
+    private List<VmDeadLockData> getFilteredByVmId(List<VmDeadLockData> savedValues, String vmId) {
+        List<VmDeadLockData> filteredValues = new ArrayList<>();
+        for (VmDeadLockData data: savedValues) {
+            if (data.getVmId().equals(vmId)) {
+                filteredValues.add(data);
+            }
+        }
+        return filteredValues;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/VmInfoPopulatorTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.dependencies.ProcessedRecords;
+import com.redhat.thermostat.storage.populator.internal.dependencies.SharedState;
+
+public class VmInfoPopulatorTest {
+
+    @Test
+    public void canHandleCorrectCollection() {
+        VmInfoPopulator populator = new VmInfoPopulator();
+        assertEquals("vm-info", populator.getHandledCollection());
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void canPopulateData() {
+        VmInfoDAO mockDAO = mock(VmInfoDAO.class);
+        SharedState state = mock(SharedState.class);
+        ProcessedRecords<String> procRecs = mock(ProcessedRecords.class);
+        String[] agents = new String[] {
+                "foo-agent1", "foo-agent2", "bar-agent3"
+        };
+        List<String> agentIdList = Arrays.asList(agents);
+        when(procRecs.getAll()).thenReturn(agentIdList);
+        when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs);
+        int perAgentVms = 44;
+        int subsetAlive = 23;
+        ConfigItem config = new ConfigItem(perAgentVms, subsetAlive, "vm-info");
+        
+        // total records inserted will be 3 * 44. 44 records per agentId
+        int totalRecords = perAgentVms * agents.length;
+        // Initially return 0, then return the expected count
+        when(mockDAO.getCount()).thenReturn(0L).thenReturn((long)totalRecords);
+        VmInfoPopulator populator = new VmInfoPopulator(mockDAO);
+        Console console = mock(Console.class);
+        PrintStream ps = mock(PrintStream.class);
+        when(console.getOutput()).thenReturn(ps);
+        populator.addPojos(config, state, console);
+        ArgumentCaptor<VmInfo> captor = ArgumentCaptor.forClass(VmInfo.class);
+        verify(mockDAO, times(totalRecords)).putVmInfo(captor.capture());
+        List<VmInfo> allInfos = captor.getAllValues();
+        assertEquals(totalRecords, allInfos.size());
+        List<VmInfo> aliveInfos = getAliveVmInfos(allInfos);
+        int totalAliveRecs = subsetAlive * agents.length;
+        assertEquals(totalAliveRecs, aliveInfos.size());
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<ProcessedRecords> procsVms = ArgumentCaptor.forClass(ProcessedRecords.class);
+        verify(state).addProcessedRecords(eq("vmId"), procsVms.capture());
+        ProcessedRecords<String> processedVms = procsVms.getValue();
+        assertEquals("Excected vmIds added to shared state", totalRecords, processedVms.getAll().size());
+    }
+    
+    @SuppressWarnings("deprecation")
+    private List<VmInfo> getAliveVmInfos(List<VmInfo> allInfos) {
+        List<VmInfo> aliveInfos = new ArrayList<>();
+        for (VmInfo info: allInfos) {
+            if (info.isAlive()) {
+                aliveInfos.add(info);
+            }
+        }
+        return aliveInfos;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfigTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig;
+
+public class PopulationConfigTest {
+    
+    private static final String NETWORK_INFO_NAME = "network-info";
+    private static final String AGENT_CONFIG_NAME = "agent-config";
+    private static final String HOST_INFO_NAME = "host-info";
+    private static final String VM_INFO_NAME = "vm-info";
+    private static final String VM_GC_STAT_NAME = "vm-gc-stats";
+    private static final String AGENT_KEY = "foo-agent-key";
+    private static final String VM_KEY = "bar-vm-key";
+
+    @Test
+    public void canParseFromFile() throws IOException {
+        String json = new String(Files.readAllBytes(new File(getClass().getResource("/testconfig").getFile()).toPath()));
+        PopulationConfig config = PopulationConfig.parseFromJsonString(json);
+        ConfigItem item = config.getConfig("agent-config");
+        assertNotNull(item);
+        assertEquals(100, item.getNumber());
+        assertEquals(20, item.getAliveItems());
+        List<ConfigItem> items = config.getConfigsTopologicallySorted();
+        assertEquals(7, items.size());
+        item = config.getConfig("vm-info");
+        assertEquals(50, item.getNumber());
+        assertEquals(40, item.getAliveItems());
+        item = config.getConfig("vm-gc-stats");
+        assertNotNull(item);
+    }
+    
+    /**
+     * Tests topological sorting of a simple DAG
+     * 
+     * <pre>
+     * agent-config -> network-info
+     *    |----------> host-info
+     *    |--> vm-info
+     *    |      `--> vm-gc-stat
+     *    `------------^
+     * </pre>
+     * 
+     * @throws IOException
+     */
+    @Test
+    public void testTopogicalSort() throws IOException {
+        List<ConfigItem> records = buildGoodRecords();
+        List<Relationship> rels = buildGoodRels();
+        PopulationConfig pc = PopulationConfig.createFromLists(records, rels);
+        List<ConfigItem> topSortedList = pc.getConfigsTopologicallySorted();
+        assertAgentConfigBeforeNetworkInfo(topSortedList);
+        assertAgentConfigBeforeHostInfo(topSortedList);
+        assertAgentConfigBeforeVmInfo(topSortedList);
+        assertVmInfoBeforeVmGcStat(topSortedList);
+        assertAgentConfigBeforeVmGcStat(topSortedList);
+    }
+    
+    private void assertAgentConfigBeforeVmGcStat(List<ConfigItem> topSortedList) {
+        assertTrue(isABeforeB(AGENT_CONFIG_NAME, VM_GC_STAT_NAME, topSortedList));
+    }
+
+    private void assertVmInfoBeforeVmGcStat(List<ConfigItem> topSortedList) {
+        assertTrue(isABeforeB(VM_INFO_NAME, VM_GC_STAT_NAME, topSortedList));
+    }
+
+    private void assertAgentConfigBeforeVmInfo(List<ConfigItem> topSortedList) {
+        assertTrue(isABeforeB(AGENT_CONFIG_NAME, VM_INFO_NAME, topSortedList));
+    }
+
+    private void assertAgentConfigBeforeHostInfo(List<ConfigItem> topSortedList) {
+        assertTrue(isABeforeB(AGENT_CONFIG_NAME, HOST_INFO_NAME, topSortedList));
+    }
+
+    private void assertAgentConfigBeforeNetworkInfo(List<ConfigItem> topSortedList) {
+        assertTrue(isABeforeB(AGENT_CONFIG_NAME, NETWORK_INFO_NAME, topSortedList));
+    }
+    
+    private boolean isABeforeB(String a, String b, List<ConfigItem> list) {
+        int idxA = -1;
+        int idxB = -1;
+        for (int i = 0; i < list.size(); i++) {
+            ConfigItem item = list.get(i);
+            if (item.getName().equals(a)) {
+                if (idxA >= 0) {
+                    throw new AssertionError("Illegal state. Re-assigning idxA!");
+                }
+                idxA = i;
+            }
+            if (item.getName().equals(b)) {
+                if (idxB >= 0) {
+                    throw new AssertionError("Illegal state. Re-assigning idxB!");
+                }
+                idxB = i;
+            }
+        }
+        return idxA < idxB;
+    }
+
+    private List<Relationship> buildGoodRels() {
+        List<Relationship> relationships = new LinkedList<>();
+        Relationship agentConfigToNetworkInfo = new Relationship(AGENT_CONFIG_NAME, NETWORK_INFO_NAME, AGENT_KEY);
+        relationships.add(agentConfigToNetworkInfo);
+        Relationship agentConfigToVmGcStat = new Relationship(AGENT_CONFIG_NAME, VM_GC_STAT_NAME, AGENT_KEY);
+        relationships.add(agentConfigToVmGcStat);
+        Relationship agentConfigToHostInfo = new Relationship(AGENT_CONFIG_NAME, HOST_INFO_NAME, AGENT_KEY);
+        relationships.add(agentConfigToHostInfo);
+        Relationship agentConfigToVmInfo = new Relationship(AGENT_CONFIG_NAME, VM_INFO_NAME, AGENT_KEY);
+        relationships.add(agentConfigToVmInfo);
+        Relationship vmInfoToVmGcStat = new Relationship(VM_INFO_NAME, VM_GC_STAT_NAME, VM_KEY);
+        relationships.add(vmInfoToVmGcStat);
+        return relationships;
+    }
+
+    private List<ConfigItem> buildGoodRecords() {
+        List<ConfigItem> records = new ArrayList<>();
+        ConfigItem agentConfig = new ConfigItem(10, 3, AGENT_CONFIG_NAME);
+        records.add(agentConfig);
+        ConfigItem hostInfo = new ConfigItem(3, 0, HOST_INFO_NAME);
+        records.add(hostInfo);
+        ConfigItem networkInfo = new ConfigItem(100, 0, NETWORK_INFO_NAME);
+        records.add(networkInfo);
+        ConfigItem vmGcStat = new ConfigItem(23, 0, VM_GC_STAT_NAME);
+        records.add(vmGcStat);
+        ConfigItem vmInfo = new ConfigItem(10, 0, VM_INFO_NAME);
+        records.add(vmInfo);
+        return records;
+    }
+
+    /**
+     * Tests topological sorting with a cycle. Expected to fail.
+     */
+    @Test(expected = AssertionError.class)
+    public void testTopogicalSortCycle() throws IOException {
+        List<ConfigItem> records = buildGoodRecords();
+        List<Relationship> rels = buildGoodRels();
+        // add a cycle between vm-info -> host-info -> agent-config
+        Relationship cyclePartOne = new Relationship(VM_INFO_NAME, HOST_INFO_NAME, VM_KEY);
+        rels.add(cyclePartOne);
+        Relationship cyclePartTwo = new Relationship(HOST_INFO_NAME, AGENT_CONFIG_NAME, AGENT_KEY);
+        rels.add(cyclePartTwo);
+        PopulationConfig pc = PopulationConfig.createFromLists(records, rels);
+        // This is expected to fail
+        pc.getConfigsTopologicallySorted();
+    }
+    
+    @Test(expected = PopulationConfig.InvalidConfigurationException.class)
+    public void testTopogicalSortIncomingCollectionMissing() throws IOException {
+        List<ConfigItem> records = buildGoodRecords();
+        // remove vm-gc-stat records config which has an incoming edge
+        // from agent-config and vm-info
+        int deleteIdx = -1;
+        for (int i = 0; i < records.size(); i++) {
+            ConfigItem item = records.get(i);
+            if (item.getName().equals(VM_GC_STAT_NAME)) {
+                deleteIdx = i;
+                break;
+            }
+        }
+        assertTrue("Expected vm-gc-stat to be in records config", deleteIdx >= 0);
+        records.remove(deleteIdx);
+        List<Relationship> rels = buildGoodRels();
+        PopulationConfig pc = PopulationConfig.createFromLists(records, rels);
+        pc.getConfigsTopologicallySorted();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/ConfigItemTypeAdapterTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.ConfigItemTypeAdapter;
+
+public class ConfigItemTypeAdapterTest {
+
+    private Gson gson;
+    
+    @Before
+    public void setup() {
+        gson= new GsonBuilder()
+                .registerTypeAdapter(ConfigItem.class, new ConfigItemTypeAdapter())
+                .create();
+    }
+    
+    @Test
+    public void testBasicNonNull() {
+        ConfigItem item = gson.fromJson("{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}", ConfigItem.class);
+        assertEquals("config-item", item.getName());
+        assertEquals(3, item.getNumber());
+        assertEquals(1, item.getAliveItems());
+    }
+    
+    @Test(expected = IllegalArgumentException.class)
+    public void testBasicNegativeNumber() {
+        gson.fromJson("{ \"name\": \"config-item\", \"number\": -3, \"alive\": 1}", ConfigItem.class);
+    }
+    
+    @Test(expected = IllegalArgumentException.class)
+    public void testBasicNegativeAlive() {
+        gson.fromJson("{ \"name\": \"config-item\", \"number\": 10, \"alive\": -1}", ConfigItem.class);
+    }
+    
+    @Test(expected = IllegalArgumentException.class)
+    public void testBasicAliveGreaterThanNumber() {
+        // alive > number. Expected strict subset
+        gson.fromJson("{ \"name\": \"config-item\", \"number\": 10, \"alive\": 11}", ConfigItem.class);
+    }
+    
+    @Test
+    public void testBasicNullAlive() {
+        ConfigItem item = gson.fromJson("{ \"name\": \"config-item\", \"number\": 3}", ConfigItem.class);
+        assertEquals("config-item", item.getName());
+        assertEquals(3, item.getNumber());
+        assertEquals(ConfigItem.UNSET, item.getAliveItems());
+    }
+    
+    @Test
+    public void testArray() {
+        ConfigItem[] items = gson.fromJson("[{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}," +
+                "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]", ConfigItem[].class);
+        assertEquals("config-item", items[0].getName());
+        assertEquals(3, items[0].getNumber());
+        assertEquals(1, items[0].getAliveItems());
+        assertEquals("agent-config", items[1].getName());
+        assertEquals(10, items[1].getNumber());
+        assertEquals(3, items[1].getAliveItems());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapterTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.storage.populator.internal.config.ConfigItem;
+import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig;
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.ConfigItemTypeAdapter;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.PopulationConfigTypeAdapterFactory;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.RelationShipTypeAdapter;
+
+public class PopulationConfigTypeAdapterTest {
+
+    private Gson gson;
+    
+    @Before
+    public void setup() {
+        gson= new GsonBuilder()
+                .registerTypeAdapter(Relationship.class, new RelationShipTypeAdapter())
+                .registerTypeAdapter(ConfigItem.class, new ConfigItemTypeAdapter())
+                .registerTypeAdapterFactory(new PopulationConfigTypeAdapterFactory())
+                .create();
+    }
+    
+    @Test
+    public void canParseSimpleNoRelationships() throws Exception {
+        String json = "{ \"records\": " +
+                "[{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}," +
+                "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]" +
+                "}";
+        PopulationConfig config = gson.fromJson(json, PopulationConfig.class);
+        ConfigItem item = config.getConfig("config-item");
+        assertEquals(3, item.getNumber());
+        assertEquals(1, item.getAliveItems());
+        assertEquals("config-item", item.getName());
+        item = config.getConfig("agent-config");
+        assertEquals(10, item.getNumber());
+        assertEquals(3, item.getAliveItems());
+        assertEquals("agent-config", item.getName());
+    }
+    
+    @Test
+    public void canParseSimpleWithRelationships() throws Exception {
+        String json = "{ \"records\": " +
+                "[{ \"name\": \"config-item\", \"number\": 3, \"alive\": 1}," +
+                "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]," +
+                " \"relationships\": "+
+                "[{ \"from\": \"config-item\", \"to\": \"agent-config\", \"key\": \"foo\"}]" +
+                "}";
+        PopulationConfig config = gson.fromJson(json, PopulationConfig.class);
+        ConfigItem item = config.getConfig("config-item");
+        assertEquals(3, item.getNumber());
+        assertEquals(1, item.getAliveItems());
+        assertEquals("config-item", item.getName());
+        item = config.getConfig("agent-config");
+        assertEquals(10, item.getNumber());
+        assertEquals(3, item.getAliveItems());
+        assertEquals("agent-config", item.getName());
+        // Do something that uses relationships
+        List<ConfigItem> sorted = config.getConfigsTopologicallySorted();
+        ConfigItem first = sorted.get(0);
+        assertEquals("config-item", first.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapterTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.config.typeadapter;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+import com.redhat.thermostat.storage.populator.internal.config.typeadapter.RelationShipTypeAdapter;
+
+public class RelationShipTypeAdapterTest {
+
+    private Gson gson;
+    
+    @Before
+    public void setup() {
+        gson= new GsonBuilder()
+                .registerTypeAdapter(Relationship.class, new RelationShipTypeAdapter())
+                .create();
+    }
+    
+    @Test
+    public void testBasicNonNull() {
+        Relationship rel = gson.fromJson("{ \"from\": \"foo\", \"to\": \"bar\", \"key\": \"baz\"}", Relationship.class);
+        assertEquals("foo", rel.getFrom());
+        assertEquals("bar", rel.getTo());
+        assertEquals("baz", rel.getKey());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/dependencies/RelationshipTest.java	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.populator.internal.dependencies;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship;
+
+public class RelationshipTest {
+
+    @Test
+    public void testEquals() {
+        Relationship one = new Relationship("foo", "bar", "key");
+        Relationship two = new Relationship("foo", "bar", "key");
+        Relationship different = new Relationship("foo", "bar", "something");
+        assertTrue(one.equals(two));
+        assertTrue(one.equals(one));
+        assertFalse(one.equals(different));
+        assertFalse(one.equals(null));
+        assertTrue(two.equals(one));
+    }
+    
+    @Test
+    public void testHashCode() {
+        Relationship one = new Relationship("foo", "bar", "key");
+        Relationship two = new Relationship("foo", "bar", "key");
+        Relationship different = new Relationship("foo", "bar", "something");
+        assertEquals(one.hashCode(), two.hashCode());
+        assertFalse(different.hashCode() == one.hashCode());
+        assertFalse(two.hashCode() == different.hashCode());
+        assertEquals(one.hashCode(), one.hashCode());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/resources/invalid-config.json	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,20 @@
+{
+  "records": [
+    {
+      "name": "foo",
+      "number": 1
+    },
+    {
+      "name": "bar",
+      "number": 5
+    }
+  ],
+
+  "relationships": [
+    {
+      "from": "foo",
+      "to": "bar",
+      "key": "tar"
+    }
+  ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/resources/testconfig	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,55 @@
+{
+"records":
+[
+{
+ "name": "vm-gc-stats",
+ "number": 1000,
+ "alive": 1000
+},
+{
+ "name": "agent-config",
+ "number": 100,
+ "alive": 20
+},
+{
+ "name": "host-info",
+ "number": 10
+},
+{
+ "name": "cpu-stats",
+ "number": 50000
+},
+{
+ "name": "memory-stats",
+ "number": 50000
+},
+{
+ "name": "network-info",
+ "number": 4
+},
+{
+ "name": "vm-info",
+ "number": 50,
+ "alive": 40
+}
+],
+"relationships":
+[
+{ "from": "agent-config",
+  "to": "vm-info",
+  "key": "agentId"
+},
+{ "from": "agent-config",
+  "to": "host-info",
+  "key": "agentId"
+},
+{ "from": "agent-config",
+  "to": "network-info",
+  "key": "agentId"
+},
+{ "from": "vm-info",
+  "to": "vm-gc-stats",
+  "key": "vmId"
+}
+]
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/command/src/test/resources/valid-config.json	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,54 @@
+{
+    "records": [
+       {
+         "name": "agent-config",
+         "number": 2,
+         "alive": 2
+       },
+       {
+         "name": "host-info",
+         "number": 1
+       },
+       {
+         "name": "vm-thread-harvesting",
+         "number": 5
+       },
+       {
+         "name": "vm-info",
+         "number": 5,
+         "alive": 5 
+       },
+       {
+         "name": "network-info",
+         "number": 20
+       }
+    ],
+    
+    "relationships": [
+      {
+        "from": "agent-config",
+        "to": "vm-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "host-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "network-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "vm-thread-harvesting",
+        "key": "agentId"
+      },
+      {
+        "from": "vm-info",
+        "to": "vm-thread-harvesting",
+        "key": "vmId"
+      }
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/distribution/pom.xml	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-storage-populator</artifactId>
+    <version>1.99.10-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-storage-populator-distribution</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Thermostat storage populator plugin distribution</name>
+
+  <properties>
+    <thermostat.plugin>storage-populator</thermostat.plugin>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <dependencies>
+          <dependency>
+            <groupId>com.redhat.thermostat</groupId>
+            <artifactId>thermostat-assembly</artifactId>
+            <version>${project.version}</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>plugin-assembly</descriptorRef>
+          </descriptorRefs>
+          <appendAssemblyId>false</appendAssemblyId>
+        </configuration>
+        <executions>
+          <execution>
+            <id>assemble-plugin</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <!-- Explicitly list all plug-in artifacts, transitive dependencies
+       are not included in assembly. -->
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-storage-populator-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/distribution/thermostat-plugin.xml	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!--
+
+ Copyright 2012-2016 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.
+
+-->
+<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd">
+  <commands>
+    <command>
+      <name>storage-populator</name>
+      <summary>populates storage with dummy data</summary>
+      <description>
+      Populates storage with dummy data.
+      </description>
+      <options>
+        <option>
+          <long>config</long>
+          <short>c</short>
+          <argument>file</argument>
+          <required>true</required>
+          <description>the json config file to use</description>
+        </option>
+      </options>
+      <environments>
+        <environment>cli</environment>
+        <environment>shell</environment>
+      </environments>
+      <bundles>
+        <bundle><symbolic-name>com.redhat.thermostat.client.cli</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.storage.populator</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.storage.mongodb</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.web.common</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.web.client</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>com.redhat.thermostat.thread.collector</symbolic-name><version>${project.version}</version></bundle>
+        <bundle><symbolic-name>${osgi.compendium.bundle.symbolic-name}</symbolic-name><version>${osgi.compendium.osgi-version}</version></bundle>
+        <bundle><symbolic-name>org.apache.httpcomponents.httpcore</symbolic-name><version>${httpcomponents.core.version}</version></bundle>
+        <bundle><symbolic-name>org.apache.httpcomponents.httpclient</symbolic-name><version>${httpcomponents.client.version}</version></bundle>
+        <bundle><symbolic-name>com.google.gson</symbolic-name><version>${gson.version}</version></bundle>
+        <bundle><symbolic-name>org.mongodb.mongo-java-driver</symbolic-name><version>${mongo-driver.osgi-version}</version></bundle>
+        <bundle><symbolic-name>org.apache.commons.beanutils</symbolic-name><version>${commons-beanutils.version}</version></bundle>
+        <bundle><symbolic-name>org.apache.commons.codec</symbolic-name><version>${commons-codec.osgi-version}</version></bundle>
+        <bundle><symbolic-name>org.apache.commons.collections</symbolic-name><version>${commons-collections.version}</version></bundle>
+        <bundle><symbolic-name>org.apache.commons.logging</symbolic-name><version>${commons-logging.version}</version></bundle>
+      </bundles>
+    </command>
+  </commands>
+</plugin>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/storage-populator/pom.xml	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-devel-modules</artifactId>
+    <version>1.99.10-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-storage-populator</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Thermostat Storage Populating Support</name>
+
+  <modules>
+    <module>command</module>
+    <module>distribution</module>
+  </modules>
+
+</project>
+
--- a/distribution/assembly/all-plugin-assembly.xml	Wed May 04 17:30:06 2016 +0200
+++ b/distribution/assembly/all-plugin-assembly.xml	Thu May 05 10:37:43 2016 -0400
@@ -55,6 +55,7 @@
         <include>com.redhat.thermostat:thermostat-notes-distribution</include>
         <include>com.redhat.thermostat:thermostat-numa-distribution</include>
         <include>com.redhat.thermostat:thermostat-storage-profile-distribution</include>
+        <include>com.redhat.thermostat:thermostat-storage-populator-distribution</include>
         <include>com.redhat.thermostat:thermostat-thread-distribution</include>
         <include>com.redhat.thermostat:thermostat-validate-distribution</include>
         <include>com.redhat.thermostat:thermostat-setup-distribution</include>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/config/storage-populator/population-config-example-simple-threads.json	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,54 @@
+{
+    "records": [
+       {
+         "name": "agent-config",
+         "number": 2,
+         "alive": 2
+       },
+       {
+         "name": "host-info",
+         "number": 1
+       },
+       {
+         "name": "vm-thread-harvesting",
+         "number": 5
+       },
+       {
+         "name": "vm-info",
+         "number": 5,
+         "alive": 5 
+       },
+       {
+         "name": "network-info",
+         "number": 20
+       }
+    ],
+    
+    "relationships": [
+      {
+        "from": "agent-config",
+        "to": "vm-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "host-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "network-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "vm-thread-harvesting",
+        "key": "agentId"
+      },
+      {
+        "from": "vm-info",
+        "to": "vm-thread-harvesting",
+        "key": "vmId"
+      }
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/config/storage-populator/population-config-example-simple.json	Thu May 05 10:37:43 2016 -0400
@@ -0,0 +1,40 @@
+{
+    "records": [
+       {
+         "name": "agent-config",
+         "number": 100,
+         "alive": 20
+       },
+       {
+         "name": "host-info",
+         "number": 1
+       },
+       {
+         "name": "vm-info",
+         "number": 50,
+         "alive": 40
+       },
+       {
+         "name": "network-info",
+         "number": 50
+       }
+    ],
+    
+    "relationships": [
+      {
+        "from": "agent-config",
+        "to": "vm-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "host-info",
+        "key": "agentId"
+      },
+      {
+        "from": "agent-config",
+        "to": "network-info",
+        "key": "agentId"
+      }
+    ]
+}
--- a/distribution/pom.xml	Wed May 04 17:30:06 2016 +0200
+++ b/distribution/pom.xml	Thu May 05 10:37:43 2016 -0400
@@ -209,6 +209,7 @@
                   <filtering>true</filtering>
                   <includes>
                     <include>shell-command/shell-prompt.conf</include>
+                    <include>storage-populator/*.json</include>
                     <include>platform/*.json</include>
                     <include>thermostat-gui/*.json</include>
                   </includes>
@@ -548,6 +549,12 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-storage-populator-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-thread-distribution</artifactId>
       <version>${project.version}</version>
       <type>zip</type>