changeset 2625:703a2e1f90be

Remove server-side web storage Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-March/022522.html
author Elliott Baron <ebaron@redhat.com>
date Tue, 21 Mar 2017 18:47:16 -0400
parents 56eebd386be2
children 40903f2b0759
files distribution/pom.xml web/endpoint-plugin/distribution/pom.xml web/endpoint-plugin/distribution/thermostat-plugin.xml web/endpoint-plugin/pom.xml web/endpoint-plugin/web-service/pom.xml web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/Activator.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoader.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DoNothingLifecycleListener.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfiguration.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/LocaleResources.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListener.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommand.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommand.java web/endpoint-plugin/web-service/src/main/resources/com/redhat/thermostat/web/endpoint/internal/strings.properties web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/ActivatorTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoaderTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncherTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/LocaleResourcesTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListenerTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommandTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommandTest.java web/pom.xml web/server/pom.xml web/server/src/main/java/com/redhat/thermostat/web/server/CategoryManager.java web/server/src/main/java/com/redhat/thermostat/web/server/ConfigurationFinder.java web/server/src/main/java/com/redhat/thermostat/web/server/CursorManager.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistryFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementManager.java web/server/src/main/java/com/redhat/thermostat/web/server/PropertySettingServletContextListener.java web/server/src/main/java/com/redhat/thermostat/web/server/StoppableTimer.java web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryImpl.java web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryProvider.java web/server/src/main/java/com/redhat/thermostat/web/server/TimerRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/TokenManager.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/AbstractFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/AgentIdFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/BasicRole.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallback.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/FilterResult.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/HostnameFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallback.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallback.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/RolePrincipal.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/StatementFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmIdFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmUsernameFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/WebStoragePathHandler.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipal.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModule.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModule.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModule.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidationException.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidator.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/AbstractContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerName.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerVersion.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/JettyContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfo.java web/server/src/main/webapp/WEB-INF/web.xml web/server/src/test/java/com/redhat/thermostat/web/server/CategoryManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/ConfigurationFinderTest.java web/server/src/test/java/com/redhat/thermostat/web/server/CursorManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/KnownCategoryRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/PreparedStatementManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/PropertySettingServletContextListenerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/TimerRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/TokenManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndPointUnitTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebstorageEndpointTestUtils.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/AgentIdFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallbackTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/HostnameFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallbackTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactoryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/RolePrincipalTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmIdFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmUsernameFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipalTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModuleTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModuleTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidatorTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModuleTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/RolesAmenderTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/SimpleCallBackHandler.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubFailureDelegateLoginModule.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubSuccessDelegateLoginModule.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/ContainerVersionTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/JettyContainerInfoTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactoryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfoTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfoTest.java web/server/src/test/resources/broken_test_roles.properties web/server/src/test/resources/broken_test_roles2.properties web/server/src/test/resources/properties_module_test_roles.properties web/server/src/test/resources/properties_module_test_users.properties web/server/src/test/resources/test_roles.properties web/server/src/test/resources/test_users.properties web/war/pom.xml web/war/src/main/resources/logging.properties web/war/src/main/webapp-tomcat7/META-INF/context.xml web/war/src/main/webapp-tomcat8/META-INF/context.xml web/war/src/main/webapp/WEB-INF/jetty-web.xml web/war/src/main/webapp/WEB-INF/web.xml
diffstat 122 files changed, 0 insertions(+), 17498 deletions(-) [+]
line wrap: on
line diff
--- a/distribution/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ b/distribution/pom.xml	Tue Mar 21 18:47:16 2017 -0400
@@ -485,15 +485,6 @@
         <artifactId>thermostat-web-client</artifactId>
         <version>${project.version}</version>
     </dependency>
-    <!-- depend on the web archive to be built in order
-         to be able to copy the exploded war into the
-         image directory -->
-    <dependency>
-        <groupId>com.redhat.thermostat</groupId>
-        <artifactId>thermostat-web-war</artifactId>
-        <version>${project.version}</version>
-        <type>war</type>
-    </dependency>
     <dependency>
         <groupId>com.redhat.thermostat</groupId>
         <artifactId>thermostat-system-backend</artifactId>
@@ -610,12 +601,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-web-endpoint-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-killvm-distribution</artifactId>
       <version>${project.version}</version>
       <type>zip</type>
--- a/web/endpoint-plugin/distribution/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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-web-endpoint</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-endpoint-distribution</artifactId>
-  <packaging>pom</packaging>
-
-  <name>Thermostat Web Embedded Servlet Container Endpoint Distribution</name>
-  
-  <properties>
-    <thermostat.plugin>embedded-web-endpoint</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-web-endpoint-plugin</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-webapp</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-io</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-util</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-security</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-http</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-servlet</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-xml</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-jaas</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.toolchain</groupId>
-      <artifactId>jetty-schemas</artifactId>
-      <version>${jetty-schemas.version}</version>
-    </dependency>
-    <!-- This will likely have to match what jetty-project's pom uses -->
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>javax.servlet-api</artifactId>
-      <version>${jetty.javax.servlet.osgi.version}</version>
-    </dependency>
-  </dependencies>
-
-</project>
-
--- a/web/endpoint-plugin/distribution/thermostat-plugin.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-<?xml version="1.0"?>
-<!--
-
- Copyright 2012-2017 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>web-storage-service</name>
-      <summary>start mongodb storage, an embedded servlet container and an agent</summary>
-      <description>
-        Start mongodb storage, an embedded servlet container with the web
-        archive deployed and then connect an agent to this web endpoint. Do all
-        this as a foreground process. On exit, shut them all down.
-      </description>
-      <command-groups>
-        <command-group>thermostat-core</command-group>
-      </command-groups>
-      <environments>
-        <environment>cli</environment>
-      </environments>
-      <bundles>
-        <!-- Dependencies of the jetty-based web endpoint plugin -->
-        <bundle><symbolic-name>com.redhat.thermostat.web.endpoint</symbolic-name><version>${project.version}</version></bundle>
-        <!-- Required for running agent on top of http.
-             It should be the equivalent of $THERMOSTAT_HOME/etc/commands/agent.properties -->
-        <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.storage.mongodb</symbolic-name><version>${project.version}</version></bundle>
-      </bundles>
-    </command>
-    <command>
-      <name>web-storage</name>
-      <summary>start backing storage and deploy the web endpoint in a servlet container</summary>
-      <description>
-        Start mongodb storage, an embedded servlet container with the web
-        archive deployed as a foreground process. On exit, shut them down.
-      </description>
-      <command-groups>
-        <command-group>thermostat-core</command-group>
-      </command-groups>
-      <environments>
-        <environment>cli</environment>
-      </environments>
-      <bundles>
-        <bundle><symbolic-name>com.redhat.thermostat.web.endpoint</symbolic-name><version>${project.version}</version></bundle>
-     </bundles>
-    </command>
-  </commands>
-</plugin>
-
--- a/web/endpoint-plugin/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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-web</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-endpoint</artifactId>
-  <packaging>pom</packaging>
-
-  <name>Thermostat Web Embedded Servlet Container Endpoint</name>
-
-  <modules>
-    <module>distribution</module>
-    <module>web-service</module>
-  </modules>
-
-</project>
-
--- a/web/endpoint-plugin/web-service/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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-web-endpoint</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-endpoint-plugin</artifactId>
-
-  <packaging>bundle</packaging>
-
-  <name>Thermostat Web Embedded Servlet Container Endpoint Core</name>
-  
-  <dependencies>
-    <!-- Plain OSGi -->
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-      <scope>provided</scope>
-    </dependency>
-
-    <!-- The war which we are going to deploy in embedded jetty -->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-web-war</artifactId>
-      <version>${project.version}</version>
-      <!-- thermostat-web-war has the attachClasses config set to true.
-           This allows us to use it here. In addition to the war a
-           file thermostat-web-war-<VERSION>-classes.jar is created
-           that way. -->
-      <classifier>classes</classifier>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-launcher</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <!-- The embedded servlet container we use -->
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-jaas</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-webapp</artifactId>
-      <version>${jetty.version}</version>
-    </dependency>
-    <!-- declarative services -->
-    <dependency>
-      <groupId>org.apache.felix</groupId>
-      <artifactId>org.apache.felix.scr.annotations</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    
-    <!-- test scoped deps -->
-    <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-common-test</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-SymbolicName>com.redhat.thermostat.web.endpoint</Bundle-SymbolicName>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <Bundle-Activator>com.redhat.thermostat.web.endpoint.internal.Activator</Bundle-Activator>
-            <!-- need to declare bundles explicitly since the automatisms fail if an embedded jetty
-                 -->
-            <Import-Package>
-              javax.servlet,
-              javax.servlet.http,
-              org.eclipse.jetty.server,
-              org.eclipse.jetty.http,
-              org.eclipse.jetty.xml,
-              org.eclipse.jetty.util,
-              org.eclipse.jetty.io,
-              org.eclipse.jetty.webapp,
-              org.eclipse.jetty.security,
-              org.eclipse.jetty.servlet,
-              org.eclipse.jetty.servlet.listener,
-              org.eclipse.jetty.jaas,
-              *,
-            </Import-Package>
-            <Private-Package>
-              com.redhat.thermostat.web.endpoint.internal              
-            </Private-Package>
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-scr-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>generate-scr-scrdescriptor</id>
-            <goals>
-              <goal>scr</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-
-</project>
-
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/Activator.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.common.cli.CommandRegistry;
-import com.redhat.thermostat.common.cli.CommandRegistryImpl;
-
-public class Activator implements BundleActivator {
-
-    private CommandRegistry reg;
-
-    @Override
-    public void start(final BundleContext context) throws Exception {
-        reg = new CommandRegistryImpl(context);
-        reg.registerCommand("web-storage-service", new WebappLauncherCommand(context));
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        reg.unregisterCommands();
-    }
-}
-
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoader.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-/**
- * Asks a delegating classloader to load classes, and if not found defer to the
- * system class loader.
- */
-class DelegatingClassLoader extends ClassLoader {
-    
-    private final ClassLoader delegate;
-
-    DelegatingClassLoader(ClassLoader delegate) {
-        this.delegate = delegate;
-    }
-    
-    public Class<?> loadClass(String className) throws ClassNotFoundException {
-        try {
-            return delegate.loadClass(className);
-        } catch (ClassNotFoundException e) {
-            return getSystemClassLoader().loadClass(className);
-        }
-    }
-}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DoNothingLifecycleListener.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import org.eclipse.jetty.util.component.LifeCycle;
-import org.eclipse.jetty.util.component.LifeCycle.Listener;
-
-public class DoNothingLifecycleListener implements Listener {
-    
-    @Override
-    public void lifeCycleStopping(LifeCycle arg0) {
-        // nothing
-    }
-    
-    @Override
-    public void lifeCycleStopped(LifeCycle arg0) {
-        // nothing
-    }
-    
-    @Override
-    public void lifeCycleStarting(LifeCycle arg0) {
-        // nothing
-    }
-    
-    @Override
-    public void lifeCycleStarted(LifeCycle arg0) {
-        // nothing
-    }
-    
-    @Override
-    public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) {
-        // nothing
-    }
-
-}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfiguration.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.HostPortPair;
-import com.redhat.thermostat.common.utils.HostPortsParser;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.shared.locale.Translate;
-
-class EmbeddedServletContainerConfiguration {
-
-    private static final Logger logger = LoggingUtils.getLogger(EmbeddedServletContainerConfiguration.class);
-    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-    private final Properties systemConfiguration;
-    private final Properties userConfiguration;
-    private final CommonPaths paths;
-    
-    // Main constructor
-    EmbeddedServletContainerConfiguration(CommonPaths paths, Properties systemConfiguration, Properties userConfiguration) {
-        this.systemConfiguration = systemConfiguration;
-        this.userConfiguration = userConfiguration;
-        this.paths = paths;
-    }
-    
-    EmbeddedServletContainerConfiguration(CommonPaths paths, File sysConfig, File userConfig) {
-        this(paths, new Properties(), new Properties());
-        // init from system config if existing
-        initConfig(sysConfig, this.systemConfiguration);
-        // init from user config if existing
-        initConfig(userConfig, this.userConfiguration);
-    }
-    
-    // For testing only
-    EmbeddedServletContainerConfiguration(File systemConfiguration, File userConfiguration) throws InvalidConfigurationException {
-        this(null, systemConfiguration, userConfiguration);
-    }
-    
-    // For testing only
-    EmbeddedServletContainerConfiguration(Properties systemConfiguration, Properties userConfiguration) {
-        this(null, systemConfiguration, userConfiguration);
-    }
-    
-    /**
-     * Main Constructor
-     * 
-     * @param paths
-     * @throws InvalidConfigurationException
-     */
-    EmbeddedServletContainerConfiguration(CommonPaths paths) throws InvalidConfigurationException {
-        this(paths, getSystemWebStorageServiceConfigFile(paths), getUserWebStorageServiceConfigFile(paths));
-    }
-    
-    private static File getUserWebStorageServiceConfigFile(CommonPaths paths) throws InvalidConfigurationException {
-        return new File(paths.getUserConfigurationDirectory(), "web-storage-service.properties");
-    }
-
-    private static File getSystemWebStorageServiceConfigFile(CommonPaths paths) throws InvalidConfigurationException {
-        return new File(paths.getSystemConfigurationDirectory(), "web-storage-service.properties");
-    }
-
-    private static void initConfig(File configFile,
-            Properties configProps) {
-        try (FileInputStream configFis = new FileInputStream(configFile)) {
-            configProps.load(configFis);
-        } catch (FileNotFoundException e) {
-            // ignore, allow files to not exist on initialization
-        } catch (IOException e) {
-            throw new InvalidConfigurationException(e);
-        }
-    }
-
-    HostPortPair getHostsPortsConfig() throws InvalidConfigurationException {
-        String hostsPortsString = systemConfiguration.getProperty(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name());
-        // user config overrides system config
-        String userPortsString = userConfiguration.getProperty(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name());
-        if (userPortsString != null) {
-            hostsPortsString = userPortsString;
-        }
-        // config must not be empty in both, system AND user config
-        if (hostsPortsString == null) {
-            throw new InvalidConfigurationException(t.localize(LocaleResources.BIND_ADDRESS_NULL));
-        }
-        HostPortsParser parser = new HostPortsParser(hostsPortsString);
-        parser.parse();
-        List<HostPortPair> hostsPorts = parser.getHostsPorts();
-        if (hostsPorts.size() != 1) {
-            throw new InvalidConfigurationException("Cannot parse configuration (lists not allowed!)");
-        }
-        return hostsPorts.get(0);
-    }
-    
-    /* The path to the context where the web archive gets bound to */
-    String getContextPath() {
-        return "/thermostat/storage";
-    }
-    
-    File getAbsolutePathToExplodedWebArchive() {
-        File thermostatHome = paths.getSystemThermostatHome();
-        // The thermostat build produces an exploded war in $THERMOSTAT_HOME/webapp
-        File webArchiveDir = new File(thermostatHome, "webapp");
-        return webArchiveDir;
-    }
-    
-    boolean isBackingStorageStart() {
-        String storageProp = systemConfiguration.getProperty(ConfigKeys.START_BACKING_STORAGE.name());
-        // user config overrides system config
-        String userProp = userConfiguration.getProperty(ConfigKeys.START_BACKING_STORAGE.name());
-        if (userProp != null) {
-            storageProp = userProp;
-        }
-        if (storageProp == null) {
-            // default to true if neither system nor user config is present
-            return true;
-        }
-        return Boolean.parseBoolean(storageProp);
-    }
-    
-    boolean isEnableTLS() {
-        String sslProp = systemConfiguration.getProperty(ConfigKeys.USE_SSL.name());
-        // user config overrides system config
-        String userProp = userConfiguration.getProperty(ConfigKeys.USE_SSL.name());
-        if (userProp != null) {
-            sslProp = userProp;
-        }
-        // default to false if neither system nor user config present
-        boolean propVal = Boolean.parseBoolean(sslProp);
-        return propVal;
-    }
-    
-    String getConnectionUrl() throws InvalidConfigurationException {
-        String httpPrefix = "http";
-        if (isEnableTLS()) {
-            httpPrefix = httpPrefix + "s";
-        }
-        HostPortPair hostPort = getHostsPortsConfig();
-        String host = hostPort.getHost();
-        if (host.indexOf(':') >= 0) {
-            // host is an IPv6 literal, enclose with '[' and ']' in order to
-            // be rfc3986 conformant
-            host = "[" + host + "]";
-        }
-        String connectUrl = String.format("%s://%s:%s%s", httpPrefix, host, hostPort.getPort(), getContextPath());
-        logger.log(Level.FINE, "Using agent connection URL '" + connectUrl + "'");
-        return connectUrl;
-    }
-    
-    String getAbsolutePathToJaasConfig() throws InvalidConfigurationException {
-        File etcPath = paths.getSystemConfigurationDirectory();
-        File thermostatJaasConf = new File(etcPath, "thermostat_jaas.conf");
-        try {
-            return thermostatJaasConf.getCanonicalPath();
-        } catch (IOException e) {
-            throw new InvalidConfigurationException(e);
-        }
-    }
-    
-    boolean hasRequestLogConfig() {
-        return getLogFileFromProperties() != null;
-    }
-    
-    String getAbsolutePathToRequestLog() throws InvalidConfigurationException {
-        String logFileName = getLogFileFromProperties();
-        if (logFileName == null) {
-            // no config
-            return null;
-        }
-        File userLogsPath = paths.getUserLogDirectory();
-        File requestLog = new File(userLogsPath, logFileName);
-        return requestLog.getAbsolutePath();
-    }
-    
-    private String getLogFileFromProperties() {
-        String logFileName = systemConfiguration.getProperty(ConfigKeys.REQUEST_LOG_FILENAME.name());
-        String userPotentialFileName = userConfiguration.getProperty(ConfigKeys.REQUEST_LOG_FILENAME.name());
-        if (userPotentialFileName != null) {
-            logFileName = userPotentialFileName;
-        }
-        if (logFileName == null) {
-            // Not set
-            return null;
-        }
-        return logFileName;
-    }
-    
-    static enum ConfigKeys {
-        /* String: The bind address. host:port format */
-        SERVLET_CONTAINER_BIND_ADDRESS,
-        /* Boolean: If set to "true" makes the embedded servlet container
-         * boot up with SSL support. It uses config in ssl.properties for
-         * keystore et al.
-         */
-        USE_SSL,
-        /* Filename of the request log. It's relative to thermostat's
-         * logs directory.
-         */
-        REQUEST_LOG_FILENAME,
-        /*
-         * Determine whether backing storage should get started too
-         */
-        START_BACKING_STORAGE
-    }
-}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.concurrent.CountDownLatch;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.net.ssl.SSLContext;
-
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.NCSARequestLog;
-import org.eclipse.jetty.server.SecureRequestCustomizer;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.server.handler.RequestLogHandler;
-import org.eclipse.jetty.util.component.LifeCycle;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.webapp.WebAppContext;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-
-import com.redhat.thermostat.common.ssl.SSLContextFactory;
-import com.redhat.thermostat.common.ssl.SslInitException;
-import com.redhat.thermostat.common.utils.HostPortPair;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-
-class JettyContainerLauncher {
-    
-    private static final Logger logger = LoggingUtils.getLogger(JettyContainerLauncher.class);
-    static final String JAAS_CONFIG_PROP = "java.security.auth.login.config";
-    
-    private final EmbeddedServletContainerConfiguration config;
-    private final SSLConfiguration sslConfig;
-    private Server server;
-    private Thread serverThread;
-    private boolean isStartupSuccessFul = true;
-    
-    JettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-        this.config = config;
-        this.sslConfig = sslConfig;
-    }
-    
-    
-    void startContainer(final CountDownLatch contextStartedLatch) {
-        serverThread = new Thread(new Runnable() {
-
-            @Override
-            public void run() {
-                // Make the class loader aware of the osgi env. By default webapps use
-                // the set TCCL as parent. Note that a plain WebAppClassLoader is not sufficient. Mainly because of classes
-                // jetty itself is using (from the servlet API, other bundles etc). 
-                //
-                // It's a simple delegating class loader. If the OSGi loader (the loader of this
-                // class) doesn't find the class, we delegate to the system class loader.
-                // 
-                // Note that this also assumes proper wiring of the endpoint bundle. That should be
-                // the case by using explicit instructions for the maven-bundle-plugin
-                // and starting all required jetty bundles on boot.
-                //
-                // See also this bug for some discussion:
-                // https://github.com/eclipse/jetty.project/issues/705
-                ClassLoader osgiLoader = JettyContainerLauncher.class.getClassLoader();
-                Thread.currentThread().setContextClassLoader(new DelegatingClassLoader(osgiLoader));
-                try {
-                    startContainerAndDeployWar(contextStartedLatch);
-                } finally {
-                    Thread.currentThread().setContextClassLoader(null);
-                }
-            }
-            
-        });
-        serverThread.start();
-    }
-    
-    boolean isStartupSuccessFul() {
-        return isStartupSuccessFul;
-    }
-    
-    void stopContainer() {
-        try {
-            server.stop();
-            server.join();
-            serverThread.join();
-        } catch (Exception e) {
-            logger.log(Level.INFO, e.getMessage(), e);
-        }
-    }
-
-    private void startContainerAndDeployWar(final CountDownLatch contextStartedLatch) {
-        // Since we call this in a thread and we wait for a countDown() on the
-        // latch be sure to always call it in the exception case. Otherwise
-        // the thread won't exit.
-        try {
-            doStartContainerAndDeployWar(contextStartedLatch);
-        } catch (Exception e) {
-            isStartupSuccessFul = false;
-            logger.log(Level.WARNING, e.getMessage(), e);
-            contextStartedLatch.countDown();
-        }
-    }
-    
-    private void doStartContainerAndDeployWar(final CountDownLatch contextStartedLatch) throws Exception {
-        HostPortPair ipPort = null;
-        try {
-            ipPort = config.getHostsPortsConfig();
-        } catch (InvalidConfigurationException e) {
-            logger.log(Level.SEVERE, e.getMessage(), e);
-            isStartupSuccessFul = false;
-            contextStartedLatch.countDown();
-            return;
-        }
-        server = new Server();
-        // Set up the connector with SSL enabled if so configured
-        ServerConnector connector = getServerConnector();
-        
-        // Set host and port
-        connector.setHost(ipPort.getHost());
-        connector.setPort(ipPort.getPort());
-        server.addConnector(connector);
-            
-        File webArchiveDir = config.getAbsolutePathToExplodedWebArchive();
-        if (!webArchiveDir.exists()) {
-            String msg = String.format("Exploded web archive '%s' not found, exitting!",
-                    webArchiveDir.getCanonicalFile().getAbsolutePath());
-            logger.log(Level.SEVERE, msg);
-            isStartupSuccessFul = false;
-            contextStartedLatch.countDown();
-            return;
-        }
-        WebAppContext ctx = new WebAppContext(webArchiveDir.getAbsolutePath(), config.getContextPath());
-        // Jetty insists on a webdefault.xml file. If the file is not found,
-        // it fails to boot the embedded server. We work around this by writing
-        // a temp file and convincing it to use that. The file content comes
-        // from jetty itself, so it should always be there.
-        Bundle bundle = FrameworkUtil.getBundle(WebAppContext.class);
-        URL uri = bundle.getResource("/org/eclipse/jetty/webapp/webdefault.xml");
-        logger.log(Level.INFO, 
-                uri == null ?
-                        "webdefault.xml file not found!" :
-                            "found file in: " + uri.toExternalForm());
-        File tempWebDefaults = File.createTempFile("jetty-webdefault", ".xml");
-        tempWebDefaults.deleteOnExit();
-        
-        writeWebDefaults(tempWebDefaults, uri);
-
-        // Jetty/OpenJDK requires this string to be a forward-slash separated path, even on windows
-        ctx.setDefaultsDescriptor("file:///" + tempWebDefaults.getAbsolutePath().replace('\\', '/'));
-        
-        // Make server startup fail if context cannot be deployed.
-        // Please don't change this.
-        ctx.setThrowUnavailableOnStartupException(true);
-        
-        // Wait for the context to be up and running
-        ctx.addLifeCycleListener(new DoNothingLifecycleListener() {
-            @Override
-            public void lifeCycleStarted(LifeCycle arg0) {
-                contextStartedLatch.countDown();
-            }
-            
-            @Override
-            public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) {
-                isStartupSuccessFul = false;
-                contextStartedLatch.countDown();
-            }
-        });
-        configureJaas();
-        // Configure the context handler with request logging if 
-        // so desired.
-        configureRequestLog(ctx);
-        
-        server.start();
-    }
-
-    private void configureRequestLog(WebAppContext ctx) {
-        if (config.hasRequestLogConfig()) {
-            HandlerCollection handlers = new HandlerCollection();
-            ContextHandlerCollection contexts = new ContextHandlerCollection();
-            RequestLogHandler requestLogHandler = new RequestLogHandler();
-            handlers.setHandlers(new Handler[] { contexts, ctx,
-                    requestLogHandler });
-            server.setHandler(handlers);
-    
-            String logPath = config.getAbsolutePathToRequestLog();
-            NCSARequestLog requestLog = new NCSARequestLog(logPath);
-            requestLog.setRetainDays(90);
-            requestLog.setAppend(true);
-            requestLog.setExtended(false);
-            TimeZone tz = Calendar.getInstance().getTimeZone();
-            requestLog.setLogTimeZone(tz.getID());
-            requestLogHandler.setRequestLog(requestLog);
-            logger.log(Level.FINEST, "Using jetty request log: " + logPath);
-        } else {
-            // no request logging just use the context as handler
-            server.setHandler(ctx);
-        }
-    }
-
-    private ServerConnector getServerConnector()
-            throws InvalidConfigurationException, SslInitException {
-        ServerConnector connector;
-        if (config.isEnableTLS()) {
-            logger.log(Level.FINEST, "Enabling TLS enabled web storage endpoint");
-            
-            // HTTP Configuration
-            HttpConfiguration http_config = new HttpConfiguration();
-            http_config.setSecureScheme("https");
-            
-            // SSL HTTP Configuration
-            HttpConfiguration https_config = new HttpConfiguration(http_config);
-            https_config.addCustomizer(new SecureRequestCustomizer());
-
-            SslContextFactory sslContextFactory = new SslContextFactory();
-            SSLContext serverContext = SSLContextFactory.getServerContext(sslConfig);
-            sslContextFactory.setSslContext(serverContext);
-            // SSL Connector
-            connector = new ServerConnector(server,
-                new SslConnectionFactory(sslContextFactory,"http/1.1"),
-                new HttpConnectionFactory(https_config));
-        } else {
-            // non-SSL
-            connector = new ServerConnector(server);
-        }
-        return connector;
-    }
-
-
-    private void writeWebDefaults(File tempWebDefaults, URL uri) {
-        try (FileOutputStream fout = new FileOutputStream(tempWebDefaults);
-                InputStream in = uri.openStream();
-                BufferedInputStream bin = new BufferedInputStream(in)) {
-            byte[] buf = new byte[256];
-            int len = -1;
-            while ((len = bin.read(buf)) > 0) {
-                fout.write(buf, 0, len);
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-
-    /*
-     * Equivalent of -Djava.security.auth.login.config=$THERMOSTAT_HOME/etc/thermostat_jaas.conf
-     * 
-     * package-private for testing.
-     */
-    void configureJaas() {
-        String propVal = System.getProperty(JAAS_CONFIG_PROP);
-        // Only set JAAS config property if not already set
-        if (propVal == null) {
-            propVal = config.getAbsolutePathToJaasConfig();
-            System.setProperty(JAAS_CONFIG_PROP, propVal);
-        }
-        logger.log(Level.FINE, "Using JAAS config '" + propVal + "'");
-    }
-    
-}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/LocaleResources.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import com.redhat.thermostat.shared.locale.Translate;
-
-public enum LocaleResources {
-
-    COMMON_PATHS_UNAVAILABLE,
-    LAUNCHER_UNAVAILABLE,
-    SSL_CONFIGURATION_UNAVAILABLE,
-
-    STORAGE_WAIT_INTERRUPTED,
-    ERROR_STARTING_STORAGE,
-    ERROR_STARTING_JETTY,
-
-    BIND_ADDRESS_NULL,
-
-    STARTING_AGENT_FAILED,
-    ;
-
-    public static final String RESOURCE_BUNDLE =
-            "com.redhat.thermostat.web.endpoint.internal.strings";
-    
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
-
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListener.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import java.util.concurrent.CountDownLatch;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.tools.ApplicationState;
-
-public class StorageStartedListener implements ActionListener<ApplicationState> {
-    private final CountDownLatch storageStarted;
-    private boolean startupSuccessful;
-
-    protected StorageStartedListener(CountDownLatch latch) {
-        storageStarted = latch;
-        // Assume startup has failed initially, until a
-        // START action event is received
-        startupSuccessful = false;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-        if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) {
-            ApplicationState state = actionEvent.getActionId();
-            switch(state) {
-                case START:
-                    startupSuccessful = true;
-                    // fall-through
-                default:
-                    storageStarted.countDown();
-                    break;
-            }
-        }
-    }
-
-    public boolean isStartupSuccessful() {
-        return startupSuccessful;
-    }
-}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommand.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.logging.Logger;
-
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
-
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ExitStatus;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.ApplicationState;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.shared.locale.Translate;
-import sun.misc.Signal;
-import sun.misc.SignalHandler;
-
-@Component
-@Service(Command.class)
-@Property(name=Command.NAME, value="web-storage")
-public class WebStorageLauncherCommand extends AbstractStateNotifyingCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-    private static final Logger logger = LoggingUtils.getLogger(WebappLauncherCommand.class);
-
-    private final List<ActionListener<ApplicationState>> listeners = new ArrayList<>();
-    private final CustomSignalHandler handler = new CustomSignalHandler();
-    private final CountDownLatch shutdownLatch;
-    private JettyContainerLauncher jettyLauncher;
-
-    @Reference
-    private CommonPaths commonPaths;
-
-    @Reference
-    private Launcher launcher;
-
-    @Reference
-    private SSLConfiguration sslConfig;
-
-    @Reference
-    private ExitStatus exitStatus;
-
-    //for declarative services instantiation
-    public WebStorageLauncherCommand() {
-        this(new CountDownLatch(1));
-    }
-
-    //package private for testing
-    WebStorageLauncherCommand(CountDownLatch shutdownLatch) {
-        this.shutdownLatch = shutdownLatch;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        EmbeddedServletContainerConfiguration config = getConfiguration(commonPaths);
-        handler.setConfig(config);
-        
-        if (config.isBackingStorageStart()) {
-            startStorage();
-        }
-
-        jettyLauncher = getJettyContainerLauncher(config, sslConfig);
-        CountDownLatch webStartedLatch = new CountDownLatch(1);
-        // start web container with the web archive deployed
-        jettyLauncher.startContainer(webStartedLatch);
-        try {
-            webStartedLatch.await();
-        } catch (InterruptedException e) {
-            // ignore
-        }
-        if (!jettyLauncher.isStartupSuccessFul()) {
-            if (config.isBackingStorageStart()) {
-                stopStorage(launcher);
-            }
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_JETTY));
-        }
-
-        Signal.handle(new Signal("INT"), handler);
-        Signal.handle(new Signal("TERM"), handler);
-
-        //Wait for SIGINT/SIGTERM
-        try {
-            shutdownLatch.await();
-        } catch (InterruptedException e) {
-            handler.handle(new Signal("INT"));
-        }
-    }
-
-    private void startStorage() throws CommandException {
-        // start storage
-        final CountDownLatch storageLatch = new CountDownLatch(1);
-        StorageStartedListener storageListener = new StorageStartedListener(storageLatch);
-        listeners.add(storageListener);
-        String[] storageArgs = new String[] {
-                "storage", "--start"
-        };
-        launcher.run(storageArgs, listeners, false);
-        listeners.clear();
-        try {
-            storageLatch.await();
-        } catch (InterruptedException e) {
-            getNotifier().fireAction(ApplicationState.FAIL, e);
-            throw new CommandException(translator.localize(LocaleResources.STORAGE_WAIT_INTERRUPTED));
-        }
-        if (!storageListener.isStartupSuccessful()) {
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_STORAGE));
-        }
-    }
-
-    // testing hook
-    EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-        return new EmbeddedServletContainerConfiguration(paths);
-    }
-
-    // testing hook
-    JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-        return new JettyContainerLauncher(config, sslConfig);
-    }
-
-    // This fires up the web endpoint. No need to automatically firing up
-    // storage.
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-
-    private void stopStorage(Launcher launcher) {
-        String[] storageStopArgs = new String[] {
-                "storage", "--stop"
-        };
-        launcher.run(storageStopArgs, false);
-    }
-
-    private class CustomSignalHandler implements SignalHandler {
-
-        private EmbeddedServletContainerConfiguration config;
-        
-        @Override
-        public void handle(Signal arg0) {
-            try {
-                jettyLauncher.stopContainer();
-                if (config.isBackingStorageStart()) {
-                    stopStorage(launcher);
-                }
-            } catch (Exception ex) {
-                // We don't want any exception to hold back the signal handler, otherwise
-                // there will be no way to actually stop Thermostat.
-                ex.printStackTrace();
-            }
-            logger.fine("Web storage stopped.");
-            // Hook for integration tests. Print a well known message to stdout
-            // if verbose mode is turned on via the system property.
-            shutdown(ExitStatus.EXIT_SUCCESS);
-        }
-        
-        private void setConfig(EmbeddedServletContainerConfiguration config) {
-            this.config = config;
-        }
-    }
-
-    private void shutdown(int shutDownStatus) {
-        // Exit application
-        if (shutdownLatch != null) {
-            shutdownLatch.countDown();
-        }
-
-        this.exitStatus.setExitStatus(shutDownStatus);
-        if (shutDownStatus == ExitStatus.EXIT_SUCCESS) {
-            getNotifier().fireAction(ApplicationState.STOP);
-        } else {
-            getNotifier().fireAction(ApplicationState.FAIL);
-        }
-    }
-    
-    public void bindCommonPaths(CommonPaths commonPaths) {
-        this.commonPaths = commonPaths;
-    }
-
-    public void bindExitStatus(ExitStatus exitStatus) {
-        this.exitStatus = exitStatus;
-    }
-
-    public void bindLauncher(Launcher launcher) {
-        this.launcher = launcher;
-    }
-
-    public void bindSslConfig(SSLConfiguration sslConfig) {
-        this.sslConfig = sslConfig;
-    }
-
-    public void unbindCommonPaths(CommonPaths commonPaths) {
-        this.commonPaths = null;
-    }
-
-    public void unbindExitStatus(ExitStatus exitStatus) {
-        this.exitStatus = null;
-    }
-
-    public void unbindLauncher(Launcher launcher) {
-        this.launcher = null;
-    }
-
-    public void unbindSslConfig(SSLConfiguration sslConfig) {
-        this.sslConfig = null;
-    }
-}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommand.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.cli.Console;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.ApplicationState;
-import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.shared.locale.Translate;
-
-class WebappLauncherCommand extends AbstractStateNotifyingCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-    private static final Logger logger = LoggingUtils.getLogger(WebappLauncherCommand.class);
-    private boolean agentStarted = false;
-
-    // The time to wait after the agent finished and before the web endpoint
-    // goes down. This increases the chance of emptying the queue.
-    private static final long AGENT_SHUTDOWN_PAUSE = 200;
-    
-    private final BundleContext context;
-    private final List<ActionListener<ApplicationState>> listeners;
-
-    WebappLauncherCommand(BundleContext context) {
-        this.context = context;
-        listeners = new ArrayList<>();
-    }
-    
-    // PRE: 1. Storage set up with credentials and credentials appropriately
-    //         updated in the web archive's web.xml
-    //      2. agent.auth file appropriately set up
-    //      3. agent/client users appropriately defined in thermostat-users/
-    //         thermostat-roles.properties files.
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        ServiceReference commonPathsRef = context.getServiceReference(CommonPaths.class.getName());
-        if (commonPathsRef == null) {
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.COMMON_PATHS_UNAVAILABLE));
-        }
-        CommonPaths paths = (CommonPaths)context.getService(commonPathsRef);
-        ServiceReference launcherRef = context.getServiceReference(Launcher.class.getName());
-        if (launcherRef == null) {
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.LAUNCHER_UNAVAILABLE));
-        }
-        Launcher launcher = (Launcher) context.getService(launcherRef);
-        EmbeddedServletContainerConfiguration config = getConfiguration(paths);
-        
-        // start storage only if so desired
-        if (config.isBackingStorageStart()) {
-            startStorage(launcher);
-        }
-
-        ServiceReference sslConfigRef = context.getServiceReference(SSLConfiguration.class.getName());
-        if (sslConfigRef == null) {
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.SSL_CONFIGURATION_UNAVAILABLE));
-        }
-        SSLConfiguration sslConfig = (SSLConfiguration) context.getService(sslConfigRef);
-
-        JettyContainerLauncher jettyLauncher = getJettyContainerLauncher(config, sslConfig);
-        CountDownLatch webStartedLatch = new CountDownLatch(1);
-        // start web container with the web archive deployed
-        jettyLauncher.startContainer(webStartedLatch);
-        try {
-            webStartedLatch.await();
-        } catch (InterruptedException e) {
-            // ignore
-        }
-        if (!jettyLauncher.isStartupSuccessFul()) {
-            if (config.isBackingStorageStart()) {
-                stopStorage(launcher);
-            }
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_JETTY));
-        }
-        
-        // start agent
-        try {
-            listeners.add(new AgentStartedListener(ctx.getConsole()));
-            String[] agentArgs = new String[] {
-                "agent", "-d", config.getConnectionUrl()
-            };
-            // This blocks
-            launcher.run(agentArgs, listeners, false);
-
-            ctx.getConsole().getOutput().println("Waiting " + AGENT_SHUTDOWN_PAUSE + "MS before exiting in order to empty queues");
-            // Give the agent some time to finish it's work. Requests are
-            // queued and it increases the chance of finishing requests before
-            // exiting for sure.
-            try {
-                Thread.sleep(AGENT_SHUTDOWN_PAUSE);
-            } catch (InterruptedException e) { } // ignore
-        } finally {
-            jettyLauncher.stopContainer();
-            if (config.isBackingStorageStart()) {
-                stopStorage(launcher);
-            }
-        };
-
-        if (agentStarted) {
-            getNotifier().fireAction(ApplicationState.STOP);
-        }
-    }
-    
-    private void startStorage(Launcher launcher) throws CommandException {
-        final CountDownLatch storageLatch = new CountDownLatch(1);
-        StorageStartedListener storageListener = new StorageStartedListener(storageLatch);
-        listeners.add(storageListener);
-        String[] storageArgs = new String[] {
-                "storage", "--start"
-        };
-        launcher.run(storageArgs, listeners, false);
-        listeners.clear();
-        try {
-            storageLatch.await();
-        } catch (InterruptedException e) {
-            getNotifier().fireAction(ApplicationState.FAIL, e);
-            throw new CommandException(translator.localize(LocaleResources.STORAGE_WAIT_INTERRUPTED));
-        }
-        if (!storageListener.isStartupSuccessful()) {
-            getNotifier().fireAction(ApplicationState.FAIL);
-            throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_STORAGE));
-        }
-    }
-
-    // testing hook
-    EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-        return new EmbeddedServletContainerConfiguration(paths);
-    }
-
-    // testing hook
-    JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-        return new JettyContainerLauncher(config, sslConfig);
-    }
-
-    // This fires up the web endpoint. No need to automatically firing up
-    // storage.
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-    
-    private void stopStorage(Launcher launcher) {
-        String[] storageStopArgs = new String[] {
-                "storage", "--stop"
-        };
-        launcher.run(storageStopArgs, false);
-    }
-
-    private class AgentStartedListener implements ActionListener<ApplicationState> {
-
-        private final Console console;
-
-        private AgentStartedListener(Console console) {
-            this.console = console;
-        }
-
-        @Override
-        public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-            if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) {
-                AbstractStateNotifyingCommand agent = (AbstractStateNotifyingCommand) actionEvent.getSource();
-                // Implementation detail: there is a single AgentCommand instance registered
-                // as an OSGi service. We remove ourselves as listener so that we don't get
-                // notified in the case that the command is invoked by some other means later.
-                agent.getNotifier().removeActionListener(this);
-
-                ApplicationState state = actionEvent.getActionId();
-                // propagate the Agent ActionEvent
-                switch(state) {
-                    case START:
-                        agentStarted = true;
-                        logger.fine("Agent started via web-storage-service. Agent ID was: " + actionEvent.getPayload());
-                        getNotifier().fireAction(ApplicationState.START, actionEvent.getPayload());
-                        break;
-                    case FAIL:
-                        console.getError().println(translator.localize(LocaleResources.STARTING_AGENT_FAILED).getContents());
-                        getNotifier().fireAction(ApplicationState.FAIL, actionEvent.getPayload());
-                        break;
-                    case STOP:
-                        getNotifier().fireAction(ApplicationState.STOP);
-                        break;
-                    default:
-                        throw new AssertionError("Unexpected state " + state);
-                }
-            }
-        }
-    }
-
-}
--- a/web/endpoint-plugin/web-service/src/main/resources/com/redhat/thermostat/web/endpoint/internal/strings.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-COMMON_PATHS_UNAVAILABLE = CommonPaths unavailable.
-LAUNCHER_UNAVAILABLE = Launcher Unavailable
-SSL_CONFIGURATION_UNAVAILABLE = SSLConfiguration Unavailable
-STORAGE_WAIT_INTERRUPTED = Interrupted waiting for storage
-ERROR_STARTING_STORAGE = Starting mongodb storage failed
-ERROR_STARTING_JETTY = Failed to start embedded jetty instance
-BIND_ADDRESS_NULL = CONFIG_LISTEN_ADDRESS must be specified.
-STARTING_AGENT_FAILED = Thermostat agent failed to start. See logs for details.
-
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/ActivatorTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.testutils.StubBundleContext;
-import com.redhat.thermostat.web.endpoint.internal.Activator;
-import com.redhat.thermostat.web.endpoint.internal.WebappLauncherCommand;
-
-public class ActivatorTest {
-
-    @Test
-    public void verifyCommandIsRegistered() throws Exception {
-        StubBundleContext context = new StubBundleContext();
-        Activator activator = new Activator();
-        activator.start(context);
-        assertTrue(context.isServiceRegistered(Command.class.getName(), WebappLauncherCommand.class));
-        activator.stop(context);
-        assertFalse(context.isServiceRegistered(Command.class.getName(), WebappLauncherCommand.class));
-    }
-}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoaderTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import org.junit.Test;
-
-public class DelegatingClassLoaderTest {
-
-    @Test
-    public void verifyClassloaderDelegationFailsForNotExistingClass() throws Exception {
-        ClassLoader mockLoader = mock(ClassLoader.class);
-        DelegatingClassLoader delegateLoader = new DelegatingClassLoader(mockLoader);
-        String notExistingClassName = "com.redhat.thermostat.not.existing.FooClass";
-        doThrow(ClassNotFoundException.class).when(mockLoader).loadClass(eq(notExistingClassName));
-        try {
-            delegateLoader.loadClass(notExistingClassName);
-            fail("should not have found class " + notExistingClassName);
-        } catch (ClassNotFoundException e) {
-            // pass
-            verify(mockLoader).loadClass(eq(notExistingClassName));
-        }
-    }
-    
-    @Test
-    public void verifyClassloaderDelegationWorksForExistingClass() throws Exception {
-        ClassLoader mockLoader = mock(ClassLoader.class);
-        DelegatingClassLoader webappLoader = new DelegatingClassLoader(mockLoader);
-        // This class is not really there, but the fake class loader does not
-        // throw a CNFE
-        String className = "com.redhat.thermostat.not.existing.FooClass";
-        try {
-            Class<?> clazz = webappLoader.loadClass(className);
-            assertNull(clazz);
-        } catch (ClassNotFoundException e) {
-            fail("should have been able to load class since mock classloader does not throw CNFE");
-        }
-        verify(mockLoader).loadClass(eq(className));
-    }
-    
-    @Test
-    public void verifySystemClassIsResolvable() throws Exception {
-    	ClassLoader mockLoader = mock(ClassLoader.class);
-    	DelegatingClassLoader delegateLoader = new DelegatingClassLoader(mockLoader);
-    	String className = "javax.security.auth.login.LoginContext";
-    	doThrow(ClassNotFoundException.class).when(mockLoader).loadClass(eq(className));
-    	try {
-    		Class<?> clazz = delegateLoader.loadClass(className);
-    		assertNotNull(clazz);
-    	} catch (ClassNotFoundException e) {
-    		fail("should have been able to load system class " + className);
-    	}
-    }
-    
-}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,390 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.File;
-import java.util.Properties;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.utils.HostPortPair;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration.ConfigKeys;
-
-public class EmbeddedServletContainerConfigurationTest {
-
-    /*
-     * empty configs defaults to false
-     */
-    @Test
-    public void canGetSSLConfigNothingSpecified() {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertFalse(config.isEnableTLS());
-    }
-
-    /*
-     * Verifies that user config overrides system config
-     */
-    @Test
-    public void canGetUserSSLConfig() {
-        Properties systemConfig = new Properties();
-        systemConfig.put(ConfigKeys.USE_SSL.name(), "false");
-        Properties userConfig = new Properties();
-        userConfig.put(ConfigKeys.USE_SSL.name(), "true");
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertTrue(config.isEnableTLS());
-    }
-
-    /*
-     * Empty configs defaults to true
-     */
-    @Test
-    public void canGetIsBackingStorageStartNothingSpecified() {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertTrue(config.isBackingStorageStart());
-    }
-
-    /*
-     * System config should be taken into account. No override by user config.
-     */
-    @Test
-    public void canGetIsBackingStorageStartSystemSpecified() {
-        Properties systemConfig = new Properties();
-        systemConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "false");
-        Properties userConfig = new Properties();
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertFalse(config.isBackingStorageStart());
-    }
-
-    /*
-     * User config overrides system.
-     */
-    @Test
-    public void canGetIsBackingStorageStartUserOverridesSystem() {
-        Properties systemConfig = new Properties();
-        systemConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "false");
-        Properties userConfig = new Properties();
-        userConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "true");
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertTrue(config.isBackingStorageStart());
-    }
-
-    /*
-     * No system config only user config.
-     */
-    @Test
-    public void canGetIsBackingStorageStartUserOverridesNoSystemConfig() {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        userConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "false");
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertFalse(config.isBackingStorageStart());
-    }
-
-    /*
-     * Verifies that system config works
-     */
-    @Test
-    public void canGetSystemSSLConfig() {
-        Properties systemConfig = new Properties();
-        systemConfig.put(ConfigKeys.USE_SSL.name(), "true");
-        Properties userConfig = new Properties();
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertTrue(config.isEnableTLS());
-    }
-
-    @Test
-    public void garbageSSLConfigValsDoNotFail() {
-        Properties systemConfig = new Properties();
-        systemConfig.put(ConfigKeys.USE_SSL.name(), "foo");
-        Properties userConfig = new Properties();
-        userConfig.put(ConfigKeys.USE_SSL.name(), "bar");
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertFalse(config.isEnableTLS());
-    }
-
-    /*
-     * No user config specified (empty properties) but
-     * system config has ips/ports pair.
-     */
-    @Test
-    public void canGetSystemConfigListenAddress() throws InvalidConfigurationException {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        String host = "127.0.0.1";
-        int port = 8888;
-        String systemConfigPairs = host + ":" + port;
-        systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), systemConfigPairs);
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        HostPortPair hostPort = config.getHostsPortsConfig();
-        assertEquals(host, hostPort.getHost());
-        assertEquals(port, hostPort.getPort());
-    }
-
-    /*
-     * If both system *and* user config are specified, user config wins.
-     */
-    @Test
-    public void userConfigOverridesSystemConfigListenAddress() throws InvalidConfigurationException {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        String host = "127.0.0.1";
-        int port = 8888;
-        String systemConfigPairs = host + ":" + port;
-        String userHost = "host.example.com";
-        int userPort = 3334;
-        String userConfigPairs = userHost + ":" + userPort;
-        systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), systemConfigPairs);
-        userConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), userConfigPairs);
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        HostPortPair hostPort = config.getHostsPortsConfig();
-        assertEquals(userHost, hostPort.getHost());
-        assertEquals(userPort, hostPort.getPort());
-    }
-
-    /*
-     * If neither system nor user config has the CONFIG_LISTEN_ADDRESS key
-     * config is invalid.
-     */
-    @Test(expected = InvalidConfigurationException.class)
-    public void testInvalidConfigNullListenAddress() {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        // this should throw InvalidConfigException
-        config.getHostsPortsConfig();
-    }
-
-    /*
-     * Implementation detail. The host/port parser supports parsing lists.
-     * However, in this context only one listen address can be specified. This
-     * test ensures that an InvalidConfigurationException is thrown if config
-     * contains a list.
-     */
-    @Test
-    public void testListenAddressInvalidConfigList() {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        String hostPortList = "127.0.0.1:8889,127.0.1.1:9999";
-        systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), hostPortList);
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        try {
-            config.getHostsPortsConfig();
-            fail("expected InvalidConfigurationException due to host/port list size > 1 in system config");
-        } catch (InvalidConfigurationException e) {
-            // pass
-        }
-        userConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), hostPortList);
-        systemConfig.clear();
-        config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        try {
-            config.getHostsPortsConfig();
-            fail("expected InvalidConfigurationException due to host/port list size > 1 in user config");
-        } catch (InvalidConfigurationException e) {
-            // pass
-        }
-    }
-
-    /*
-     * Config should not throw and exception on instantiation if user config
-     * file does not exist.
-     */
-    @Test
-    public void canLoadConfigWithUserFileNotExisting() throws Exception {
-        File systemFile = File.createTempFile("thermostat-tests", EmbeddedServletContainerConfigurationTest.class.getName());
-        systemFile.deleteOnExit();
-        assertTrue(systemFile.exists());
-        File userFile = new File("/thermostat/i-do-not-exists");
-        assertFalse(userFile.exists());
-        try {
-            new EmbeddedServletContainerConfiguration(systemFile, userFile);
-            // pass
-        } catch (InvalidConfigurationException e) {
-            fail("Instantiation should not throw ICE due to missing files: " + e.getMessage());
-        }
-    }
-
-    /*
-     * Config should not throw and exception on instantiation if system config
-     * file does not exist.
-     */
-    @Test
-    public void canLoadConfigWithSystemFileNotExisting() throws Exception {
-        File userFile = File.createTempFile("thermostat-tests", EmbeddedServletContainerConfigurationTest.class.getName());
-        userFile.deleteOnExit();
-        assertTrue(userFile.exists());
-        File sysFile = new File("/thermostat/i-do-not-exists");
-        assertFalse(sysFile.exists());
-        try {
-            new EmbeddedServletContainerConfiguration(sysFile, userFile);
-            // pass
-        } catch (InvalidConfigurationException e) {
-            fail("Instantiation should not throw ICE due to missing files: " + e.getMessage());
-        }
-    }
-
-    /*
-     * Config should not throw and exception on instantiation if user config
-     * and system config file does not exist.
-     */
-    @Test
-    public void canLoadConfigWithSystemAndUserFileNotExisting() {
-        File sysFile = new File("/thermostat/i-do-not-exists-system");
-        File userFile = new File("/thermostat/i-do-not-exists-user");
-        assertFalse(sysFile.exists());
-        assertFalse(userFile.exists());
-        try {
-            new EmbeddedServletContainerConfiguration(sysFile, userFile);
-            // pass
-        } catch (InvalidConfigurationException e) {
-            fail("Instantiation should not throw ICE due to missing files: " + e.getMessage());
-        }
-    }
-
-    @Test
-    public void testGetWebArchivePath() {
-        CommonPaths paths = mock(CommonPaths.class);
-        File fooThermostatHome = new File("/foo/path");
-        when(paths.getSystemThermostatHome()).thenReturn(fooThermostatHome);
-
-        // Any non-null file will do for user/system config files
-        File irrelevantForTest = new File("irrelevant");
-
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, irrelevantForTest, irrelevantForTest);
-        File expected = new File(fooThermostatHome, "webapp");
-        File actual = config.getAbsolutePathToExplodedWebArchive();
-        assertEquals(expected.getAbsolutePath(), actual.getAbsolutePath());
-    }
-
-    /*
-     * If a request log configuration is set, be sure config paths are available
-     */
-    @Test
-    public void verifyRequestLogConfiguration() {
-        CommonPaths paths = mock(CommonPaths.class);
-        File testUserHomeLogs = new File("/test/userhome/logs");
-        when(paths.getUserLogDirectory()).thenReturn(testUserHomeLogs);
-
-        // system config only
-        Properties userConfig = new Properties();
-        Properties systemConfig = new Properties();
-        systemConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "logfile.log");
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
-        assertTrue("Should have request log config", config.hasRequestLogConfig());
-        assertEquals(new File("/test/userhome/logs/logfile.log").getAbsolutePath(), config.getAbsolutePathToRequestLog());
-
-        // user config only
-        userConfig = new Properties();
-        systemConfig = new Properties();
-        userConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "userlogFile.log");
-        config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
-        assertTrue("Should have request log config", config.hasRequestLogConfig());
-        assertEquals(new File("/test/userhome/logs/userlogFile.log").getAbsolutePath(), config.getAbsolutePathToRequestLog());
-
-        // user and system config
-        userConfig = new Properties();
-        systemConfig = new Properties();
-        userConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "userlogFile.log");
-        systemConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "systemlogFile.log");
-        config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
-        assertTrue("Should have request log config", config.hasRequestLogConfig());
-        assertEquals("User config overrides system config",
-                new File("/test/userhome/logs/userlogFile.log").getAbsolutePath(),
-                     config.getAbsolutePathToRequestLog());
-
-        // no config
-        userConfig = new Properties();
-        systemConfig = new Properties();
-        config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
-        assertFalse("Should NOT have request log config", config.hasRequestLogConfig());
-        assertNull("No config specified",
-                     config.getAbsolutePathToRequestLog());
-    }
-
-    @Test
-    public void canGetConnectionURL() {
-        doConnectionUrlTest("http://[1fff:0:a88:85a3::ac1f]:8999/thermostat/storage", "[1fff:0:a88:85a3::ac1f]:8999", false);
-        doConnectionUrlTest("http://host1.example.com:8888/thermostat/storage", "host1.example.com:8888", false);
-        doConnectionUrlTest("https://host1.example.com:8998/thermostat/storage", "host1.example.com:8998", true);
-    }
-
-    @Test
-    public void canGetContextPath() {
-        String expectedContextPath = "/thermostat/storage";
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration((Properties)null /* unused */, (Properties)null /* unused */);
-        assertEquals(expectedContextPath, config.getContextPath());
-    }
-
-    private void doConnectionUrlTest(String expectedUrl, String hostPortToken, boolean enableSSL) {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), hostPortToken);
-        if (enableSSL) {
-            systemConfig.put(ConfigKeys.USE_SSL.name(), Boolean.TRUE.toString());
-        }
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig);
-        assertEquals(expectedUrl, config.getConnectionUrl());
-    }
-
-    @Test
-    public void canGetPathToJaasConfig() throws InvalidConfigurationException {
-        CommonPaths paths = mock(CommonPaths.class);
-        String fooThHome = "/foo/path/etc";
-        File fooThermostatHome = new File(fooThHome);
-        when(paths.getSystemConfigurationDirectory()).thenReturn(fooThermostatHome);
-
-        // Any non-null file will do for user/system config files
-        File irrelevantForTest = new File("irrelevant");
-
-        EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, irrelevantForTest, irrelevantForTest);
-        String actual = config.getAbsolutePathToJaasConfig();
-        assertEquals(new File(fooThHome + "/thermostat_jaas.conf").getAbsolutePath(), actual);
-    }
-}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncherTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import java.io.File;
-import java.util.concurrent.CountDownLatch;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.utils.HostPortPair;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration;
-import com.redhat.thermostat.web.endpoint.internal.JettyContainerLauncher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
-
-public class JettyContainerLauncherTest {
-
-    @Test
-    public void startFailsIfWebArchivePathDoesNotExist() throws InterruptedException {
-        EmbeddedServletContainerConfiguration config = mock(EmbeddedServletContainerConfiguration.class);
-        File notThere = new File("/path/not-here-go-away");
-        when(config.getAbsolutePathToExplodedWebArchive()).thenReturn(notThere);
-        HostPortPair hostPort = new HostPortPair("foo", 1111);
-        when(config.getHostsPortsConfig()).thenReturn(hostPort);
-        assertFalse(notThere.exists());
-        JettyContainerLauncher launcher = new JettyContainerLauncher(config, mock(SSLConfiguration.class));
-        CountDownLatch latch = new CountDownLatch(1);
-        launcher.startContainer(latch);
-        latch.await();
-        assertFalse(launcher.isStartupSuccessFul());
-    }
-    
-    @Test
-    public void canConfigureJaasNoPropSet() {
-        try {
-            assertNull("Precondition failed!", System.getProperty(JettyContainerLauncher.JAAS_CONFIG_PROP));
-            EmbeddedServletContainerConfiguration config = mock(EmbeddedServletContainerConfiguration.class);
-            when(config.getAbsolutePathToJaasConfig()).thenReturn("/foo/jaas.conf");
-            JettyContainerLauncher launcher = new JettyContainerLauncher(config, mock(SSLConfiguration.class));
-            launcher.configureJaas();
-            assertEquals("/foo/jaas.conf", System.getProperty(JettyContainerLauncher.JAAS_CONFIG_PROP));
-        } finally {
-            System.clearProperty(JettyContainerLauncher.JAAS_CONFIG_PROP);
-        }
-    }
-    
-    // A preconfigured jaas property should be left untouched.
-    @Test
-    public void canConfigureJaasWithPropSet() {
-        try {
-            EmbeddedServletContainerConfiguration config = mock(EmbeddedServletContainerConfiguration.class);
-            System.setProperty(JettyContainerLauncher.JAAS_CONFIG_PROP, "foo_jaas.conf");
-            JettyContainerLauncher launcher = new JettyContainerLauncher(config, mock(SSLConfiguration.class));
-            launcher.configureJaas();
-            verify(config, times(0)).getAbsolutePathToJaasConfig();
-            assertEquals("foo_jaas.conf", System.getProperty(JettyContainerLauncher.JAAS_CONFIG_PROP));
-        } finally {
-            System.clearProperty(JettyContainerLauncher.JAAS_CONFIG_PROP);
-        }
-    }
-}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/LocaleResourcesTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest;
-
-public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> {
-
-    @Override
-    protected Class<LocaleResources> getEnumClass() {
-        return LocaleResources.class;
-    }
-
-    @Override
-    protected String getResourceBundle() {
-        return LocaleResources.RESOURCE_BUNDLE;
-    }
-
-    
-}
-
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListenerTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.concurrent.CountDownLatch;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.ApplicationState;
-
-public class StorageStartedListenerTest {
-    private StorageStartedListener listener;
-    private CountDownLatch latch;
-    private ActionEvent<ApplicationState> event;
-
-    @Before
-    public void setup() {
-        latch = new CountDownLatch(1);
-        listener = new StorageStartedListener(latch);
-        event = mock(ActionEvent.class);
-        when(event.getSource()).thenReturn(mock(AbstractStateNotifyingCommand.class));
-    }
-
-    @Test
-    public void testStartAction() {
-        when(event.getActionId()).thenReturn(ApplicationState.START);
-
-        listener.actionPerformed(event);
-
-        assertTrue(listener.isStartupSuccessful());
-        assertEquals(0, latch.getCount());
-    }
-
-    @Test
-    public void testDefaultAction() {
-        when(event.getActionId()).thenReturn(ApplicationState.STOP);
-        listener.actionPerformed(event);
-
-        assertFalse(listener.isStartupSuccessful());
-        assertEquals(0, latch.getCount());
-    }
-}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommandTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,284 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import static org.junit.Assert.assertFalse;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-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.File;
-import java.util.Collection;
-import java.util.Properties;
-import java.util.concurrent.CountDownLatch;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ExitStatus;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.ApplicationState;
-import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-
-public class WebStorageLauncherCommandTest {
-
-    private static final String[] STORAGE_START_ARGS = { "storage", "--start" };
-    private static final String[] STORAGE_STOP_ARGS = { "storage", "--stop" };
-
-    private CommandContext mockCommandContext;
-    private CommonPaths mockPaths;
-    private ExitStatus mockExitStatus;
-    private Launcher mockLauncher;
-    private SSLConfiguration mockSslConfig;
-    private JettyContainerLauncher mockJettyLauncher;
-    private CountDownLatch shutdownLatch;
-
-    @Before
-    public void setup() {
-        mockCommandContext = mock(CommandContext.class);
-        mockExitStatus = mock(ExitStatus.class);
-        mockPaths = mock(CommonPaths.class);
-        mockLauncher = mock(Launcher.class);
-        mockSslConfig = mock(SSLConfiguration.class);
-
-        shutdownLatch = new CountDownLatch(1);
-
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
-
-        doAnswer(new Answer() {
-            @Override
-            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
-                AbstractStateNotifyingCommand cmd = mock(AbstractStateNotifyingCommand.class);
-                for (Object l :  captor.getValue()) {
-                    ActionEvent<ApplicationState> fakeEvent = new ActionEvent<>(cmd, ApplicationState.START);
-                    ((ActionListener<ApplicationState>)l).actionPerformed(fakeEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), captor.capture(), eq(false));
-
-
-        mockJettyLauncher = mock(JettyContainerLauncher.class);
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                CountDownLatch webStartedLatch = (CountDownLatch) invocation.getArguments()[0];
-                webStartedLatch.countDown();
-                return null;
-            }
-        }).when(mockJettyLauncher).startContainer(isA(CountDownLatch.class));
-        when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(true);
-        doNothing().when(mockJettyLauncher).stopContainer();
-    }
-
-    private void bind(WebStorageLauncherCommand command) {
-        command.bindCommonPaths(mockPaths);
-        command.bindExitStatus(mockExitStatus);
-        command.bindLauncher(mockLauncher);
-        command.bindSslConfig(mockSslConfig);
-    }
-
-    @Test
-    public void testIsStorageRequired() {
-        WebStorageLauncherCommand command = new WebStorageLauncherCommand();
-
-        assertFalse(command.isStorageRequired());
-    }
-
-    @Test(expected = CommandException.class)
-    public void testRunCommandWithNoConfigListenAddressSpecified() throws Exception {
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        final EmbeddedServletContainerConfiguration testConfig = new EmbeddedServletContainerConfiguration(mockPaths, systemConfig, userConfig);
-
-        WebStorageLauncherCommand command = new WebStorageLauncherCommand() {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return testConfig;
-            }
-        };
-
-        bind(command);
-        command.run(mockCommandContext);
-    }
-
-    @Test(expected = CommandException.class)
-    public void testRunCommandWithWebArchiveNotExisting() throws Exception {
-        CommonPaths paths = mock(CommonPaths.class);
-
-        File thermostatHomeNotExisting = mock(File.class);
-        when(paths.getSystemThermostatHome()).thenReturn(thermostatHomeNotExisting);
-
-        Properties systemConfig = new Properties();
-        Properties userConfig = new Properties();
-        userConfig.put(EmbeddedServletContainerConfiguration.ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), "127.0.0.1:8888");
-        final EmbeddedServletContainerConfiguration testConfig = new EmbeddedServletContainerConfiguration(mockPaths, systemConfig, userConfig);
-
-        WebStorageLauncherCommand command = new WebStorageLauncherCommand() {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return testConfig;
-            }
-        };
-        bind(command);
-        command.run(mockCommandContext);
-    }
-
-    @Test
-    public void testRunOnce() throws CommandException {
-        boolean startBackingStorage = true;
-        doTestRunOnce(startBackingStorage);
-    }
-
-    @Test
-    public void testRunOnceNoBackingStorage() throws CommandException {
-        boolean startBackingStorage = false;
-        doTestRunOnce(startBackingStorage);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void doTestRunOnce(boolean startBackingStorage) throws CommandException {
-        final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class);
-        when(mockConfig.isBackingStorageStart()).thenReturn(startBackingStorage);
-        when(mockConfig.getConnectionUrl()).thenReturn("Test String");
-
-        WebStorageLauncherCommand command = new WebStorageLauncherCommand(shutdownLatch) {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return mockConfig;
-            }
-
-            @Override
-            JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-                return mockJettyLauncher;
-            }
-        };
-
-        bind(command);
-
-        shutdownLatch.countDown();
-
-        command.run(mockCommandContext);
-
-        int numberOfTimesBackingStorage = 0;
-        if (startBackingStorage) {
-            numberOfTimesBackingStorage++;
-        }
-        verify(mockLauncher, times(numberOfTimesBackingStorage)).run(eq(STORAGE_START_ARGS), isA(Collection.class), eq(false));
-    }
-
-    @Test(expected = CommandException.class)
-    public void testStorageFailStart()  throws CommandException {
-        final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class);
-        when(mockConfig.getConnectionUrl()).thenReturn("Test String");
-        when(mockConfig.isBackingStorageStart()).thenReturn(true);
-
-        WebStorageLauncherCommand command = new WebStorageLauncherCommand(shutdownLatch) {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return mockConfig;
-            }
-
-            @Override
-            JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-                return mockJettyLauncher;
-            }
-        };
-
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
-
-        doAnswer(new Answer() {
-            @Override
-            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
-                AbstractStateNotifyingCommand cmd = mock(AbstractStateNotifyingCommand.class);
-                for (Object l :  captor.getValue()) {
-                    ActionEvent<ApplicationState> fakeEvent = new ActionEvent<>(cmd, ApplicationState.FAIL);
-                    ((ActionListener<ApplicationState>)l).actionPerformed(fakeEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), captor.capture(), eq(false));
-
-        bind(command);
-
-        shutdownLatch.countDown();
-
-        command.run(mockCommandContext);
-    }
-
-
-    @Test(expected = CommandException.class)
-    public void testWebContainerFailStart()  throws CommandException {
-        final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class);
-        when(mockConfig.getConnectionUrl()).thenReturn("Test String");
-
-        WebStorageLauncherCommand command = new WebStorageLauncherCommand(shutdownLatch) {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return mockConfig;
-            }
-
-            @Override
-            JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-                return mockJettyLauncher;
-            }
-        };
-        bind(command);
-
-        when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(false);
-        shutdownLatch.countDown();
-
-        command.run(mockCommandContext);
-
-        verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), eq(false));
-        verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), eq(false));
-    }
-}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommandTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,668 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.endpoint.internal;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-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.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.CountDownLatch;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.cli.Console;
-import com.redhat.thermostat.testutils.NotImplementedException;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandContextFactory;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.ApplicationState;
-import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.testutils.StubBundleContext;
-import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration.ConfigKeys;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-public class WebappLauncherCommandTest {
-
-    private TestLogHandler handler;
-    private Logger logger;
-    private Launcher mockLauncher;
-    private WebappLauncherCommand cmd;
-    private CommandContext mockCommandContext;
-    private ByteArrayOutputStream stdErrOut;
-    private JettyContainerLauncher mockJettyLauncher;
-
-    private static ActionEvent<ApplicationState> mockActionEvent;
-    private static Collection<ActionListener<ApplicationState>> listeners;
-
-    private static final String[] STORAGE_START_ARGS = { "storage", "--start" };
-    private static final String[] STORAGE_STOP_ARGS = { "storage", "--stop" };
-    private static final String[] AGENT_ARGS = {"agent", "-d", "Test String"};
-    private static final String AGENT_ID = "Test ID";
-
-    @Before
-    public void setup() {
-        mockActionEvent = mock(ActionEvent.class);
-        when(mockActionEvent.getPayload()).thenReturn(new String("Test String"));
-        AbstractStateNotifyingCommand mockNotifyingCommand = mock(AbstractStateNotifyingCommand.class);
-        ActionNotifier<ApplicationState> mockNotifier = mock(ActionNotifier.class);
-        when(mockNotifyingCommand.getNotifier()).thenReturn(mockNotifier);
-        when(mockActionEvent.getSource()).thenReturn(mockNotifyingCommand);
-
-        mockLauncher = mock(Launcher.class);
-        StubBundleContext context = new StubBundleContext();
-        context.registerService(CommonPaths.class, mock(CommonPaths.class), null);
-        context.registerService(Launcher.class, mockLauncher, null);
-        context.registerService(SSLConfiguration.class, mock(SSLConfiguration.class), null);
-        final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class);
-        when(mockConfig.isBackingStorageStart()).thenReturn(true);
-        when(mockConfig.getConnectionUrl()).thenReturn("Test String");
-        mockJettyLauncher = mock(JettyContainerLauncher.class);
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                CountDownLatch webStartedLatch = (CountDownLatch) invocation.getArguments()[0];
-                webStartedLatch.countDown();
-                return null;
-            }
-        }).when(mockJettyLauncher).startContainer(isA(CountDownLatch.class));
-        when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(true);
-        doNothing().when(mockJettyLauncher).stopContainer();
-        cmd = new WebappLauncherCommand(context) {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return mockConfig;
-            }
-
-            @Override
-            JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) {
-                return mockJettyLauncher;
-            }
-        };
-
-        mockCommandContext = mock(CommandContext.class);
-        Console console = mock(Console.class);
-        stdErrOut = new ByteArrayOutputStream();
-        PrintStream errOut = new PrintStream(stdErrOut);
-        when(console.getError()).thenReturn(errOut);
-        when(console.getOutput()).thenReturn(errOut);
-        when(mockCommandContext.getConsole()).thenReturn(console);
-    }
-
-    @After
-    public void tearDown() {
-        if (handler != null && logger != null) {
-            logger.removeHandler(handler);
-            handler = null;
-        }
-    }
-
-    @Test
-    public void testIsStorageRequired() {
-        WebappLauncherCommand cmd = new WebappLauncherCommand(null /* not used */);
-        assertFalse(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testRunCommandWithNoConfigListenAddressSpecified() {
-        CommonPaths paths = mock(CommonPaths.class);
-
-        File thermostatHomeNotExisting = new File("/thermostat-home/not-existing");
-        when(paths.getSystemThermostatHome()).thenReturn(thermostatHomeNotExisting);
-        // config needs non-null paths for configuration files. It does not
-        // matter if that file actually exists. Using the fake THERMOSTAT_HOME
-        // variable will do.
-        File nonNullConfigFile = new File("doesn't matter");
-
-        String matchString = "CONFIG_LISTEN_ADDRESS";
-        runTestWithPathsAndConfigFiles(paths, nonNullConfigFile, nonNullConfigFile, matchString);
-    }
-
-    @Test
-    public void testRunCommandWithWebArchiveNotExisting() throws Exception {
-        CommonPaths paths = mock(CommonPaths.class);
-
-        File thermostatHomeNotExisting = new File("/thermostat-home/not-existing");
-        when(paths.getSystemThermostatHome()).thenReturn(thermostatHomeNotExisting);
-        File nonNullSysConfig = new File("no matter");
-
-        Properties userProperties = new Properties();
-        userProperties.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), "127.0.0.1:8888");
-        File userPropsTempFile = File.createTempFile("thermostat", WebappLauncherCommandTest.class.getName());
-        userPropsTempFile.deleteOnExit();
-        try (FileOutputStream fout = new FileOutputStream(userPropsTempFile)) {
-            userProperties.store(fout, "test props");
-        } catch (IOException e) {
-            // ignore
-        }
-        assertTrue(userPropsTempFile.exists());
-
-        String matchString = "Exploded web archive";
-        runTestWithPathsAndConfigFiles(paths, userPropsTempFile, nonNullSysConfig, matchString);
-    }
-
-    private void runTestWithPathsAndConfigFiles(final CommonPaths paths, final File userConfig,
-                                                final File systemConfig, final String matchString) {
-        StubBundleContext context = new StubBundleContext();
-        context.registerService(CommonPaths.class, paths, null);
-        Launcher launcher = new TestLauncher();
-        context.registerService(Launcher.class, launcher, null);
-        context.registerService(SSLConfiguration.class, mock(SSLConfiguration.class), null);
-        final EmbeddedServletContainerConfiguration testConfig = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig);
-        WebappLauncherCommand cmd = new WebappLauncherCommand(context) {
-            @Override
-            EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) {
-                return testConfig;
-            }
-        };
-        CommandContextFactory factory = new CommandContextFactory(context);
-        CommandContext ctxt = factory.createContext(new Arguments() {
-
-            @Override
-            public List<String> getNonOptionArguments() {
-                return Collections.emptyList();
-            }
-
-            @Override
-            public boolean hasArgument(String name) {
-                return false;
-            }
-
-            @Override
-            public String getArgument(String name) {
-                return null;
-            }
-
-            @Override
-            public String getSubcommand() {
-                throw new NotImplementedException();
-            }
-        });
-        setupLogger(matchString);
-        assertFalse(handler.gotLogMessage);
-        try {
-            cmd.run(ctxt);
-            fail("Should have failed to run command");
-        } catch (CommandException e) {
-            // pass
-            assertTrue("Did not match. message was: '" + e.getMessage() + "'", handler.gotLogMessage);
-        }
-    }
-
-    @Test
-    public void testRunCommandCommonPathsNotRegistered() {
-        StubBundleContext context = new StubBundleContext();
-        cmd = new WebappLauncherCommand(context);
-        final boolean[] result = new boolean[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = true;
-                        break;
-                    case START:
-                        result[0] = false;
-                        break;
-                    case STOP:
-                        result[1] = false;
-                        break;
-                }
-            }
-        });
-        try {
-            cmd.run(mockCommandContext);
-            fail("Command should have thrown an exception");
-        } catch (CommandException e) {
-            Assert.assertTrue(e.getMessage().contains("CommonPaths unavailable."));
-        }
-
-        Assert.assertTrue("WebappLauncherCommand expected to fire FAIL event", result[0]);
-    }
-
-    @Test
-    public void testRunCommandLauncherNotRegistered() {
-        StubBundleContext context = new StubBundleContext();
-        context.registerService(CommonPaths.class, mock(CommonPaths.class), null);
-        cmd = new WebappLauncherCommand(context);
-        final boolean[] result = new boolean[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = true;
-                        break;
-                    case START:
-                        result[0] = false;
-                        break;
-                    case STOP:
-                        result[1] = false;
-                        break;
-                }
-            }
-        });
-        try {
-            cmd.run(mockCommandContext);
-            fail("Command should have thrown an exception");
-        } catch (CommandException e) {
-            Assert.assertTrue(e.getMessage().contains("Launcher Unavailable"));
-        }
-
-        Assert.assertTrue("WebappLauncherCommand expected to fire FAIL event", result[0]);
-    }
-
-    @Test
-    public void testRunCommandSSLConfigurationNotRegistered() {
-        StubBundleContext context = new StubBundleContext();
-        context.registerService(CommonPaths.class, mock(CommonPaths.class), null);
-        context.registerService(Launcher.class, mockLauncher, null);
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-
-        cmd = new WebappLauncherCommand(context);
-        final boolean[] result = new boolean[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = true;
-                        break;
-                    case START:
-                        result[0] = false;
-                        break;
-                    case STOP:
-                        result[1] = false;
-                        break;
-                }
-            }
-        });
-        try {
-            cmd.run(mockCommandContext);
-            fail("Command should have thrown an exception");
-        } catch (CommandException e) {
-            Assert.assertTrue(e.getMessage().contains("SSLConfiguration Unavailable"));
-        }
-
-        Assert.assertTrue("WebappLauncherCommand expected to fire FAIL event", result[0]);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test(timeout=1000)
-    public void testRunOnce() throws CommandException {
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
-                when(mockActionEvent.getPayload()).thenReturn(AGENT_ID);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean());
-
-        final boolean[] result = new boolean[2];
-        final String[] agentIdFound = new String[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = false;
-                        break;
-                    case START:
-                        result[0] = true;
-                        agentIdFound[0] = (String) actionEvent.getPayload();
-                        break;
-                    case STOP:
-                        result[1] = true;
-                        break;
-                }
-            }
-        });
-
-        boolean exTriggered = false;
-        try {
-            cmd.run(mockCommandContext);
-        } catch (CommandException e) {
-            exTriggered = true;
-        }
-        Assert.assertFalse(exTriggered);
-        Assert.assertTrue("Agent expected to fire START event", result[0]);
-        Assert.assertTrue("Agent expected to fire STOP event", result[1]);
-        Assert.assertEquals("Payload does not contain AgentId matching the agent started", agentIdFound[0], AGENT_ID);
-
-        verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean());
-        verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockActionEvent, times(2)).getActionId();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test(timeout=1000)
-    public void testStorageFailStart()  throws CommandException {
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-
-        final boolean[] result = new boolean[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = true;
-                        break;
-                    case START:
-                        result[0] = false;
-                        break;
-                    case STOP:
-                        result[0] = false;
-                        break;
-                }
-            }
-        });
-
-        try {
-            cmd.run(mockCommandContext);
-            fail("Command should have thrown an exception");
-        } catch (CommandException e) {
-            Assert.assertTrue(e.getMessage().contains("Starting mongodb storage failed"));
-        }
-
-        Assert.assertTrue("Agent expected to fire FAIL event", result[0]);
-
-        verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockLauncher, never()).run(eq(STORAGE_STOP_ARGS), anyBoolean());
-        verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockActionEvent, times(1)).getActionId();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test(timeout=1000)
-    public void testWebContainerFailStart()  throws CommandException {
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-
-        final boolean[] result = new boolean[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = true;
-                        break;
-                    case START:
-                        result[0] = false;
-                        break;
-                    case STOP:
-                        result[0] = false;
-                        break;
-                }
-            }
-        });
-
-        when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(false);
-
-        try {
-            cmd.run(mockCommandContext);
-            fail("Command should have thrown an exception");
-        } catch (CommandException e) {
-            Assert.assertTrue(e.getMessage().contains("Failed to start embedded jetty instance"));
-        }
-
-        Assert.assertTrue("Agent expected to fire FAIL event", result[0]);
-
-        verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean());
-        verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockActionEvent, times(1)).getActionId();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test(timeout=1000)
-    public void testAgentStartFail()  throws CommandException {
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-        doAnswer(new Answer<Void>() {
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                listeners = (Collection<ActionListener<ApplicationState>>)args[1];
-
-                when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL);
-
-                for(ActionListener<ApplicationState> listener : listeners) {
-                    listener.actionPerformed(mockActionEvent);
-                }
-                return null;
-            }
-        }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean());
-
-        final boolean[] result = new boolean[1];
-        cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() {
-            @SuppressWarnings("incomplete-switch")
-            @Override
-            public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case FAIL:
-                        result[0] = true;
-                        break;
-                    case START:
-                        result[0] = false;
-                        break;
-                    case STOP:
-                        result[0] = false;
-                        break;
-                }
-            }
-        });
-
-        boolean exTriggered = false;
-        try {
-            cmd.run(mockCommandContext);
-        } catch (CommandException e) {
-            exTriggered = true;
-        }
-        Assert.assertFalse(exTriggered);
-        Assert.assertTrue(stdErrOut.toString().contains("Thermostat agent failed to start. See logs for details."));
-
-        verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean());
-        verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean());
-        verify(mockActionEvent, times(2)).getActionId();
-    }
-
-    private void setupLogger(String matchString) {
-        logger = Logger.getLogger("com.redhat.thermostat");
-        handler = new TestLogHandler(matchString);
-        logger.addHandler(handler);
-    }
-
-    private static class TestLauncher implements Launcher {
-
-        @Override
-        public void run(String[] args, boolean inShell) {
-            // no-op
-        }
-
-        @Override
-        public void run(String[] args,
-                Collection<ActionListener<ApplicationState>> listeners,
-                boolean inShell) {
-            if (args[0].equals("storage") && args[1].equals("--start")) {
-                // start storage
-                AbstractStateNotifyingCommand cmd = mock(AbstractStateNotifyingCommand.class);
-                for (ActionListener<ApplicationState> l: listeners) {
-                    ActionEvent<ApplicationState> fakeEvent = new ActionEvent<>(cmd, ApplicationState.START);
-                    l.actionPerformed(fakeEvent);
-                }
-            }
-        }
-
-    }
-
-    private static class TestLogHandler extends Handler {
-
-        private final String matchString;
-        private boolean gotLogMessage = false;
-
-        private TestLogHandler(String matchString) {
-            this.matchString = matchString;
-        }
-
-        @Override
-        public void publish(LogRecord record) {
-            String logMessage = record.getMessage();
-            if (record.getLevel().intValue() >= Level.WARNING.intValue() &&
-                    logMessage.contains(matchString)) {
-                gotLogMessage = true;
-            };
-        }
-
-        @Override
-        public void flush() {
-            // no-op
-        }
-
-        @Override
-        public void close() throws SecurityException {
-            // no-op
-        }
-    }
-
-}
--- a/web/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ b/web/pom.xml	Tue Mar 21 18:47:16 2017 -0400
@@ -52,10 +52,7 @@
 
   <modules>
     <module>common</module>
-    <module>server</module>
     <module>client</module>
-    <module>endpoint-plugin</module>
-    <module>war</module>
   </modules>
 
 </project>
--- a/web/server/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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-web</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-server</artifactId>
-  <packaging>bundle</packaging>
-
-  <name>Thermostat Web Server</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>org.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-      <version>${jetty.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <!-- Required for JAASLoginService used in WebStorageEndpointTest -->
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-jaas</artifactId>
-      <version>${jetty.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <!-- Used in jetty8 compatibility test -->
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-plus</artifactId>
-      <version>${jetty8-tests.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-webapp</artifactId>
-      <version>${jetty.version}</version>
-      <scope>test</scope>
-    </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-storage-mongodb</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>servlet-api</artifactId>
-      <version>${javax.servlet.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>commons-fileupload</groupId>
-      <artifactId>commons-fileupload</artifactId>
-      <version>${commons-fileupload.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-      <version>${commons-io.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>commons-codec</groupId>
-      <artifactId>commons-codec</artifactId>
-      <version>${commons-codec.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-      <scope>provided</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-web-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-SymbolicName>com.redhat.thermostat.web.server</Bundle-SymbolicName>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Export-Package>
-              com.redhat.thermostat.web.server,
-              com.redhat.thermostat.web.server.auth,
-              com.redhat.thermostat.web.server.auth.spi,
-              com.redhat.thermostat.web.server.containers,
-            </Export-Package>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-</project>
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/CategoryManager.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.web.common.SharedStateId;
-
-class CategoryManager {
-    
-    private final Map<CategoryIdentifier, SharedStateId> categoryIds;
-    private final Map<SharedStateId, Category<?>> categories;
-    private int categoryIdCounter = 0;
-    
-    CategoryManager() {
-        categories = new HashMap<>();
-        categoryIds = new HashMap<>();
-    }
-    
-    // Testing only
-    CategoryManager(int initialValue) {
-        this();
-        categoryIdCounter = initialValue;
-    }
-    
-    synchronized <T extends Pojo> SharedStateId putCategory(UUID serverNonce, Category<T> category, CategoryIdentifier catId) {
-        if (categoryIds.containsKey(Objects.requireNonNull(catId))) {
-            return categoryIds.get(catId);
-        } else {
-            // add new category
-            Objects.requireNonNull(category);
-            Objects.requireNonNull(serverNonce);
-            SharedStateId newId = new SharedStateId(categoryIdCounter, serverNonce);
-            categoryIdCounter++;
-            // This really should not happen, but if it does fail early. 
-            if (categoryIdCounter == Integer.MAX_VALUE) {
-                throw new IllegalStateException("Too many categories!");
-            }
-            categoryIds.put(catId, newId);
-            categories.put(newId, category);
-            return newId;
-        }
-    }
-    
-    synchronized SharedStateId getCategoryId(CategoryIdentifier key) {
-        return categoryIds.get(Objects.requireNonNull(key));
-    }
-    
-    @SuppressWarnings("unchecked")
-    synchronized <T extends Pojo> Category<T> getCategory(SharedStateId id) {
-        return (Category<T>)categories.get(Objects.requireNonNull(id));
-    }
-    
-    static class CategoryIdentifier {
-        
-        private final String categoryName;
-        private final String dataClassName;
-        
-        CategoryIdentifier(String categoryName, String dataClassName) {
-            this.categoryName = categoryName;
-            this.dataClassName = dataClassName;
-        }
-        
-        @Override
-        public boolean equals(Object other) {
-            if (other == null || CategoryIdentifier.class != other.getClass()) {
-                return false;
-            }
-            CategoryIdentifier o = (CategoryIdentifier)other;
-            return Objects.equals(categoryName, o.categoryName) &&
-                    Objects.equals(dataClassName, o.dataClassName);
-        }
-        
-        @Override
-        public int hashCode() {
-            return Objects.hash(categoryName, dataClassName);
-        }
-    }
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/ConfigurationFinder.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.io.File;
-
-import com.redhat.thermostat.shared.config.CommonPaths;
-
-public class ConfigurationFinder {
-
-    private final CommonPaths paths;
-
-    public ConfigurationFinder(CommonPaths paths) {
-        this.paths = paths;
-    }
-
-    /** Finds the best configuration file, accessible to the process */
-    public File getConfiguration(String name) {
-        File systemFile = getConfigurationFile(paths.getSystemConfigurationDirectory(), name);
-        if (isUsable(systemFile)) {
-            return systemFile;
-        }
-        File userFile = getConfigurationFile(paths.getUserConfigurationDirectory(), name);
-        if (isUsable(userFile)) {
-            return userFile;
-        }
-        return null;
-    }
-
-    /** package-private for testing only */
-    File getConfigurationFile(File directory, String name) {
-        return new File(directory, name);
-    }
-
-    private boolean isUsable(File file) {
-        return file.isFile() && file.canRead();
-    }
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/CursorManager.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import com.redhat.thermostat.storage.core.Cursor;
-
-/**
- * Manages (query) cursors for a single user.
- * 
- */
-final class CursorManager {
-
-    public static final int CURSOR_NOT_STORED = -1;
-    private final Map<Integer, CursorHolder> cursors;
-    private final TimerRegistry registry;
-    private int cursorIdCounter;
-    
-    // test-only
-    CursorManager(TimerRegistry registry, Map<Integer, CursorHolder> cursors) {
-        this.registry = registry;
-        this.cursors = cursors;
-    }
-    
-    CursorManager(TimerRegistry registry) {
-        this.cursors = new HashMap<>();
-        this.registry = registry;
-    }
-    
-    // test-only
-    CursorManager(int cursorIdCounter) {
-        this(null);
-        this.cursorIdCounter = cursorIdCounter;
-    }
-    
-    /**
-     * Add a cursor to the map we know of if it has more results.
-     * 
-     * @param cursor The potential candidate to add to the state we keep track
-     *               of.
-     * @return The cursor ID or {@link CursorManager#CURSOR_NOT_STORED} if the
-     *         passed in cursor has no more elements.
-     */
-    synchronized int put(final Cursor<?> cursor) {
-        int cursorId = CURSOR_NOT_STORED;
-        if (cursor.hasNext()) {
-            // Be sure we don't overflow. For a long running web storage we
-            // could potentially run out of id's for a single user. However,
-            // the time between 0 and Integer.MAX_VALUE should be sufficiently
-            // large so that any given cursor expires before the id will get
-            // reused.
-            if (cursorIdCounter == Integer.MAX_VALUE) {
-                cursorIdCounter = 0; // start again from 0
-            }
-            cursorId = cursorIdCounter;
-            cursors.put(cursorId, new CursorHolder(cursor, System.currentTimeMillis()));
-            cursorIdCounter++;
-        }
-        return cursorId;
-    }
-    
-    synchronized Cursor<?> get(int cursorId) {
-        CursorHolder holder = cursors.get(cursorId);
-        if (holder == null) {
-            return null;
-        }
-        return holder.getCursor();
-    }
-    
-    synchronized void updateCursorTimeStamp(int cursorId) {
-        CursorHolder holder = cursors.get(cursorId);
-        if (holder == null) {
-            return;
-        }
-        holder.updateTimestamp();
-    }
-    
-    synchronized void removeCursor(int cursorId) {
-        cursors.remove(cursorId);
-    }
-    
-    synchronized void expireCursors() {
-        final long currentTime = System.currentTimeMillis();
-        List<Integer> expiredCursors = new ArrayList<>();
-        for (Entry<Integer, CursorHolder> entry: cursors.entrySet()) {
-            CursorHolder holder = entry.getValue();
-            if (holder.isCursorExpired(currentTime)) {
-                expiredCursors.add(entry.getKey());
-            }
-        }
-        for (Integer expiredKey: expiredCursors) {
-            cursors.remove(expiredKey);
-        }
-    }
-    
-    void startSweeperTimer() {
-        CursorTimer sweeperTimer = new CursorTimer(new CursorSweeper(this));
-        sweeperTimer.scheduleTask();
-        registry.registerTimer(sweeperTimer);
-    }
-    
-    /**
-     * 
-     * A container in order save and track cursors. This holder enables
-     * expiring cursors, as well as extending the liveness of a cursor.
-     *
-     */
-    static class CursorHolder {
-
-        private static final int MINUTES = 1000 * 60;
-        // The time out in minutes
-        static final int TIMEOUT = 3 * MINUTES;
-        
-        private final Cursor<?> cursor;
-        private long lastUpdated;
-        
-        CursorHolder(Cursor<?> cursor, long lastUpdated) {
-            this.cursor = cursor;
-            this.lastUpdated = lastUpdated;
-        }
-        
-        void updateTimestamp() {
-            this.lastUpdated = System.currentTimeMillis();
-        }
-        
-        boolean isCursorExpired(long currentTime) {
-            return checkIsCursorExpired(currentTime, TIMEOUT);
-        }
-        
-        Cursor<?> getCursor() {
-            return cursor;
-        }
-        
-        // here in order to facilitate testing
-        boolean checkIsCursorExpired(long currentTime, final int timeoutInMillis) {
-            return lastUpdated < (currentTime - timeoutInMillis);
-        }
-        
-        // test-only
-        long getLastUpdated() {
-            return lastUpdated;
-        }
-    }
-    
-    /**
-     * {@link TimerTask} which times out cursors.
-     */
-    static class CursorSweeper extends TimerTask {
-        
-        private final CursorManager manager;
-        
-        CursorSweeper(CursorManager manager) {
-            this.manager = manager;
-        }
-
-        @Override
-        public void run() {
-            manager.expireCursors();
-        }
-
-    }
-    
-    static class CursorTimer implements StoppableTimer {
-
-        private static final String NAME = NAME_PREFIX + "cursor-manager";
-        private final Timer timer;
-        private final TimerTask task;
-        boolean taskScheduled = false;
-        
-        CursorTimer(TimerTask task) {
-            this(task, new Timer(NAME));
-        }
-        
-        // for testing
-        CursorTimer(TimerTask task, Timer timer) {
-            this.timer = timer;
-            this.task = task;
-        }
-        
-        void scheduleTask() {
-            timer.scheduleAtFixedRate(task, 0, CursorHolder.TIMEOUT);
-            taskScheduled = true;
-        }
-
-        @Override
-        public void stop() {
-            timer.cancel();
-        }
-        
-    }
-    
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistry.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.auth.CategoryRegistration;
-
-/**
- * Registers trusted category names.
- *
- * @see CategoryRegistration
- * @see Category
- */
-final class KnownCategoryRegistry {
-
-    private static final ServiceLoader<CategoryRegistration> TRUSTED_CATEGORIES = ServiceLoader
-            .load(CategoryRegistration.class);
-    private final Set<String> trustedCategories;
-    
-    KnownCategoryRegistry() {
-        this(TRUSTED_CATEGORIES);
-    }
-    
-    KnownCategoryRegistry(Iterable<CategoryRegistration> registrations) {
-        trustedCategories = new HashSet<>();
-        for (CategoryRegistration reg: registrations) {
-            Set<String> currentRegs = reg.getCategoryNames();
-            // Some Set implementations throw NPEs when contains() is called on
-            // a null value. Be sure we catch NPE since those impls can't contain
-            // null values anyway.
-            try {
-                if (currentRegs.contains(null)) {
-                    String msg = "null name not allowed!";
-                    throw new IllegalStateException(msg);
-                }
-                // Pass: Not containing null values.
-            } catch (NullPointerException npe) {
-                // Pass: Set impl does not support contains checks on null
-                //       values.
-            }
-            trustedCategories.addAll(currentRegs);
-        }
-    }
-    
-    Set<String> getRegisteredCategoryNames() {
-        // return a read-only view of registered category names.
-        return Collections.unmodifiableSet(trustedCategories);
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistryFactory.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-
-package com.redhat.thermostat.web.server;
-
-/*
- * Testing aid in order to be able to inject a KnownCategoryRegistry.
- *
- */
-class KnownCategoryRegistryFactory {
-
-    private static KnownCategoryRegistry knownRegistry;
-    
-    static KnownCategoryRegistry getInstance() {
-        if (knownRegistry == null) {
-            return new KnownCategoryRegistry();
-        } else {
-            return knownRegistry;
-        }
-    }
-    
-    static void setInstance(KnownCategoryRegistry reg) {
-        knownRegistry = reg;
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.ServiceLoader;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
-
-/**
- * Registers trusted statement descriptors.
- *
- */
-final class KnownDescriptorRegistry {
-
-    private static final ServiceLoader<StatementDescriptorRegistration> TRUSTED_DESCS = ServiceLoader
-            .load(StatementDescriptorRegistration.class);
-    private final Set<String> trustedSet;
-    
-    KnownDescriptorRegistry() {
-        this(TRUSTED_DESCS);
-    }
-    
-    KnownDescriptorRegistry(Iterable<StatementDescriptorRegistration> trustedDescs) {
-        trustedSet = new HashSet<>();
-        for (StatementDescriptorRegistration reg: trustedDescs) {
-            Set<String> newCandidates = reg.getStatementDescriptors();
-            // Some Set implementations throw NPEs when contains() is called on
-            // a null value. Be sure we catch NPE since those impls can't contain
-            // null values anyway.
-            try {
-                if (newCandidates.contains(null)) {
-                    throw new IllegalStateException("null statement descriptor not acceptable!");
-                }
-                // Pass: Not containing null values.
-            } catch (NullPointerException npe) {
-                // Pass: Set impl does not support contains checks on null
-                //       values.
-            }
-            trustedSet.addAll(newCandidates);
-        }
-    }
-    
-    final Set<String> getRegisteredDescriptors() {
-        // return a read-only set of all descriptors
-        return Collections.unmodifiableSet(trustedSet);
-    }
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryFactory.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-final class KnownDescriptorRegistryFactory {
-    
-    private static KnownDescriptorRegistry reg;
-    
-    static KnownDescriptorRegistry getInstance() {
-        if (reg == null) {
-            return new KnownDescriptorRegistry();
-        } else {
-            return reg;
-        }
-    }
-    
-    static void setKnownDescriptorRegistry(KnownDescriptorRegistry reg) {
-        KnownDescriptorRegistryFactory.reg = reg;
-    }
-
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.web.common.SharedStateId;
-
-class PreparedStatementHolder<T extends Pojo> {
-
-    private final SharedStateId stmtId;
-    private final PreparedStatement<T> stmt;
-    private final Class<T> dataClass;
-    private final StatementDescriptor<T> desc;
-    
-    PreparedStatementHolder(SharedStateId stmtId, PreparedStatement<T> stmt, Class<T> dataClass, StatementDescriptor<T> desc) {
-        this.stmtId = stmtId;
-        this.stmt = stmt;
-        this.dataClass = dataClass;
-        this.desc = desc;
-    }
-
-    SharedStateId getId() {
-        return stmtId;
-    }
-
-    PreparedStatement<T> getStmt() {
-        return stmt;
-    }
-    
-    Class<T> getDataClass() {
-        return dataClass;
-    }
-
-    StatementDescriptor<T> getStatementDescriptor() {
-        return desc;
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementManager.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.web.common.SharedStateId;
-
-/**
- * Manager for {@link PreparedStatement}s which get prepared/executed via
- * {@link WebStorage}.
- *
- */
-class PreparedStatementManager {
-
-    // We have one map per server token.
-    private final Map<SharedStateId, PreparedStatementHolder<?>> preparedStatementIds;
-    private final Map<StatementDescriptor<?>, PreparedStatementHolder<?>> preparedStmts;
-    private int currentPreparedStmtId = 0;
-    
-    PreparedStatementManager() {
-        preparedStatementIds = new HashMap<>();
-        preparedStmts = new HashMap<>();
-    }
-    
-    // Test only constructor
-    PreparedStatementManager(int initialValue) {
-        this();
-        currentPreparedStmtId = initialValue;
-    }
-    
-    @SuppressWarnings("unchecked") // we are the only ones adding them
-    synchronized <T extends Pojo> PreparedStatementHolder<T> getStatementHolder(SharedStateId id) {
-        return (PreparedStatementHolder<T>)preparedStatementIds.get(Objects.requireNonNull(id));
-    }
-    
-    @SuppressWarnings("unchecked") // we are the only ones adding them
-    synchronized <T extends Pojo> PreparedStatementHolder<T> getStatementHolder(StatementDescriptor<T> desc) {
-        return (PreparedStatementHolder<T>)preparedStmts.get(Objects.requireNonNull(desc));
-    }
-    
-    /**
-     * Adds a new {@link PreparedStatementHolder} into this
-     * {@link PreparedStatementManager}. Adding an equal {@code targetDesc}
-     * statement twice will yield the same returned id.
-     * 
-     * @param serverToken
-     *            A server token used for creating a new {@link SharedStateId}
-     *            if the target statement is not already tracked.
-     * @param targetStmt
-     *            The target statement to keep track of.
-     * @param dataClass
-     *            The data class of the target statement.
-     * @param targetDesc
-     *            The {@link StatementDescriptor} which was used for creating
-     *            the target statement {@code targetStmt}
-     * @return A unique ID identifying this statement. It's suitable to be
-     *         shared between server and client.
-     */
-    synchronized <T extends Pojo> SharedStateId createAndPutHolder(
-                                                             UUID serverToken,
-                                                             PreparedStatement<T> targetStmt,
-                                                             Class<T> dataClass,
-                                                             StatementDescriptor<T> targetDesc) {
-        // check if we have this descriptor already added
-        @SuppressWarnings("unchecked")
-        PreparedStatementHolder<T> holder = (PreparedStatementHolder<T>)preparedStmts.get(Objects.requireNonNull(targetDesc));
-        if (holder != null) {
-            // nothing to do
-            assert( preparedStatementIds.get(holder.getId()) != null );
-            return holder.getId();
-        }
-        // OK, must be a new statement we don't yet track
-        SharedStateId id = new SharedStateId(currentPreparedStmtId, Objects.requireNonNull(serverToken));
-        currentPreparedStmtId++;
-        // There is nothing we can do other than using a long rather than an int
-        // for the ID. That being said, having more than 2 billion *different* queries
-        // seems more than unlikely. It may very well be a bug. Either way it
-        // seems like a good idea to fail hard in order to be in the know about
-        // this situation.
-        if (currentPreparedStmtId == Integer.MAX_VALUE) {
-            throw new IllegalStateException("Too many different statements!");
-        }
-        holder = new PreparedStatementHolder<>(id,
-                                               Objects.requireNonNull(targetStmt),
-                                               Objects.requireNonNull(dataClass),
-                                               targetDesc);
-        preparedStmts.put(targetDesc, holder);
-        preparedStatementIds.put(id, holder);
-        return id;
-    }
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/PropertySettingServletContextListener.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import com.redhat.thermostat.common.Constants;
-
-/**
- * Sets the THERMOSTAT_HOME system property as 
- * configured via said context-param in web.xml.
- * <p>
- * Does not set THERMOSTAT_HOME if the system property is already defined.
- */
-public class PropertySettingServletContextListener implements
-        ServletContextListener {
-    
-    private static final String PROPERTY_NAME = "THERMOSTAT_HOME";
-
-    @Override
-    public void contextInitialized(ServletContextEvent sce) {
-        String thermostatHome = sce.getServletContext().getInitParameter(PROPERTY_NAME);
-        if (System.getProperty(PROPERTY_NAME) == null) {
-            System.setProperty(PROPERTY_NAME, thermostatHome);
-        }
-        System.setProperty(Constants.IS_PROXIED_STORAGE, Boolean.TRUE.toString());
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent sce) {
-        System.clearProperty(PROPERTY_NAME);
-        System.clearProperty(Constants.IS_PROXIED_STORAGE);
-    }
-
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StoppableTimer.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-/**
- * Interface for stoppable timers the {@link WebStorageEndPoint} uses. That is
- * all timers it uses <strong>must</strong> implement this interface and be
- * sure to register the timer via {@link TimerRegistry}.
- *
- */
-interface StoppableTimer {
-    
-    String NAME_PREFIX = "thermostat-timer-";
-    
-    /**
-     * Stops this timer and the associated thread.
-     */
-    void stop();
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-
-interface StorageFactory {
-
-    Storage getStorage(String storageClass, String storageEndpoint, CommonPaths paths, StorageCredentials creds);
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryImpl.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-
-package com.redhat.thermostat.web.server;
-
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.SSLConfiguration;
-import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-import com.redhat.thermostat.storage.core.StorageProvider;
-import com.redhat.thermostat.storage.mongodb.MongoStorageProvider;
-
-class StorageFactoryImpl {
-
-    private static Storage storage;
-
-    // Web server is not OSGi, this factory method is workaround.
-    static Storage getStorage(String storageClass, final String storageEndpoint, final CommonPaths paths,
-            final StorageCredentials creds) {
-        if (storage != null) {
-            return storage;
-        }
-        SSLConfiguration sslConf = new SSLConfigurationImpl(paths);
-        try {
-            StorageProvider provider = (StorageProvider) Class.forName(storageClass).newInstance();
-            provider.setConfig(storageEndpoint, creds, sslConf);
-            storage = provider.createStorage();
-            storage.getConnection().connect();
-            return storage;
-        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
-            // This fallback should infact not be used. But it gives us an automatic
-            // Import-Package in the OSGi descriptor, which actually *prevents* this same
-            // exception from happening (a recursive self-defeating catch-block) :-)
-            System.err.println("could not instantiate provider: " + storageClass + ", falling back to MongoStorage");
-            e.printStackTrace();
-            StorageProvider provider = new MongoStorageProvider();
-            provider.setConfig(storageEndpoint, creds, sslConf);
-            storage = provider.createStorage();
-            return storage;
-        }
-    }
-
-    // Testing hook used in WebStorageEndpointTest
-    static void setStorage(Storage storage) {
-        StorageFactoryImpl.storage = storage;
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryProvider.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-interface StorageFactoryProvider {
-
-    StorageFactory createStorageFactory();
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/TimerRegistry.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Registers {@link StoppableTimer}s and shuts them down when no longer
- * needed.
- *
- */
-class TimerRegistry {
-
-    private final List<StoppableTimer> registeredTimers;
-    
-    TimerRegistry() {
-        this(new ArrayList<StoppableTimer>());
-    }
-    
-    // for testing
-    TimerRegistry(List<StoppableTimer> timers) {
-        this.registeredTimers = timers;
-    }
-    
-    void registerTimer(StoppableTimer timer) {
-        registeredTimers.add(timer);
-    }
-    
-    void shutDown() {
-        for (StoppableTimer timer: registeredTimers) {
-            timer.stop();
-        }
-    }
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/TokenManager.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-
-package com.redhat.thermostat.web.server;
-
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Timer;
-import java.util.TimerTask;
-
-class TokenManager {
-
-    private static final int TOKEN_LENGTH = 256;
-
-    private final SecureRandom random = new SecureRandom();
-
-    private final Map<String,byte[]> tokens = Collections.synchronizedMap(new HashMap<String,byte[]>());
-
-    private final TokenManagerTimer timer;
-
-    private int timeout = 30 * 1000;
-
-    TokenManager(TimerRegistry registry) {
-        this(registry, new TokenManagerTimer());
-    }
-    
-    // for testing
-    TokenManager(TimerRegistry registry, TokenManagerTimer timer) {
-        this.timer = timer;
-        registry.registerTimer(timer);
-    }
-    
-    void setTimeout(int timeout) {
-        this.timeout = timeout;
-    }
-
-    byte[] generateToken(byte[] clientToken, String actionName) {
-        byte[] token = new byte[TOKEN_LENGTH];
-        random.nextBytes(token);
-        final String clientKey = getKey(clientToken,
-                Objects.requireNonNull(actionName));
-        tokens.put(clientKey, token);
-        scheduleRemoval(clientKey);
-        return token;
-    }
-
-    private void scheduleRemoval(final String clientKey) {
-        TimerTask task = new TimerTask() {
-            
-            @Override
-            public void run() {
-                tokens.remove(clientKey);
-            }
-        };
-        timer.schedule(task, timeout);
-    }
-    
-    private String getKey(byte[] clientToken, String actionName) {
-        try {
-            return getSha256HexString(clientToken, actionName.getBytes("UTF-8"));
-        } catch (UnsupportedEncodingException e) {
-            // If this happens, this is clearly a bug.
-            throw new RuntimeException(e);
-        }
-    }
-
-    boolean verifyToken(byte[] clientToken, byte[] candidateToken, String actionName) {
-        final String clientKey = getKey(clientToken, Objects.requireNonNull(actionName));
-        if (tokens.containsKey(clientKey)) {
-            byte[] storedToken = tokens.get(clientKey);
-            boolean verified = Arrays.equals(candidateToken, storedToken);
-            if (verified) {
-                tokens.remove(clientKey);
-            }
-            return verified;
-        }
-        return false;
-    }
-    
-    private String getSha256HexString(byte[] clientToken, byte[] actionName) {
-        MessageDigest digest;
-        try {
-            digest = MessageDigest.getInstance("SHA-256");
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(e);
-        }
-        digest.update(clientToken);
-        digest.update(actionName);
-        byte[] result = digest.digest();
-        return convertBytesToHexString(result);
-    }
-    
-    // package private for testing
-    String convertBytesToHexString(byte[] shaBytes) {
-        StringBuilder hexString = new StringBuilder();
-
-        for (byte shaByte : shaBytes) {
-            String hex = Integer.toHexString(0xff & shaByte);
-            if (hex.length() == 1) {
-                hexString.append('0');
-            }
-            hexString.append(hex);
-        }
-        
-        return hexString.toString();
-    }
-
-    // Used for testing only
-    byte[] getStoredToken(String sha256) {
-        return tokens.get(sha256);
-    }
-
-    static class TokenManagerTimer implements StoppableTimer {
-        
-        private static final String NAME = NAME_PREFIX + "token-manager";
-        private final Timer timer;
-        
-        // for testing
-        TokenManagerTimer(Timer timer) {
-            this.timer = timer;
-        }
-
-        TokenManagerTimer() {
-            this(new Timer(NAME));
-        }
-
-        @Override
-        public void stop() {
-            timer.cancel();
-        }
-        
-        void schedule(TimerTask task, int timeout) {
-            timer.schedule(task, timeout);
-        }
-        
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1110 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.lang.reflect.Array;
-import java.net.URLDecoder;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.UUID;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.fileupload.FileItem;
-import org.apache.commons.fileupload.FileItemFactory;
-import org.apache.commons.fileupload.FileUploadException;
-import org.apache.commons.fileupload.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
-import com.redhat.thermostat.storage.config.FileStorageCredentials;
-import com.redhat.thermostat.storage.core.BasicBatchCursor;
-import com.redhat.thermostat.storage.core.Categories;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.CategoryAdapter;
-import com.redhat.thermostat.storage.core.CloseOnSave;
-import com.redhat.thermostat.storage.core.Connection;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DataModifyingStatement;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.IllegalPatchException;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.PreparedParameters;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Statement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-import com.redhat.thermostat.storage.model.AggregateResult;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinaryLogicalOperator;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.web.common.PreparedStatementResponseCode;
-import com.redhat.thermostat.web.common.SharedStateId;
-import com.redhat.thermostat.web.common.WebPreparedStatement;
-import com.redhat.thermostat.web.common.WebPreparedStatementResponse;
-import com.redhat.thermostat.web.common.WebQueryResponse;
-import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory;
-import com.redhat.thermostat.web.server.CategoryManager.CategoryIdentifier;
-import com.redhat.thermostat.web.server.auth.FilterResult;
-import com.redhat.thermostat.web.server.auth.PrincipalCallback;
-import com.redhat.thermostat.web.server.auth.PrincipalCallbackFactory;
-import com.redhat.thermostat.web.server.auth.Roles;
-import com.redhat.thermostat.web.server.auth.UserPrincipal;
-import com.redhat.thermostat.web.server.auth.WebStoragePathHandler;
-import com.redhat.thermostat.web.server.containers.ServletContainerInfo;
-import com.redhat.thermostat.web.server.containers.ServletContainerInfoFactory;
-
-@SuppressWarnings("serial")
-public class WebStorageEndPoint extends HttpServlet {
-
-    // This is an ugly hack in order to allow for testing of batched querying.
-    static int DEFAULT_QUERY_BATCH_SIZE = Cursor.DEFAULT_BATCH_SIZE;
-    
-    static final String CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX = "thermostat-cmdc-grant-";
-    static final String FILES_READ_GRANT_ROLE_PREFIX = "thermostat-files-grant-read-filename-";
-    static final String FILES_WRITE_GRANT_ROLE_PREFIX = "thermostat-files-grant-write-filename-";
-    private static final String TOKEN_MANAGER_TIMEOUT_PARAM = "token-manager-timeout";
-    private static final String TOKEN_MANAGER_KEY = "token-manager";
-    private static final String CURSOR_MANAGER_KEY = "cursor-manager";
-    static final String CATEGORY_MANAGER_KEY = "category-manager";
-    static final String PREPARED_STMT_MANAGER_KEY = "prepared-stmt-manager";
-    static final String SERVER_TOKEN_KEY = "server-token";
-
-    // our strings can contain non-ASCII characters. Use UTF-8
-    // see also PR 1344
-    private static final String RESPONSE_JSON_CONTENT_TYPE = "application/json; charset=UTF-8";
-    private static final String CREDENTIALS_FILE = "web.auth";
-
-    private static final Logger logger = LoggingUtils.getLogger(WebStorageEndPoint.class);
-
-    private final Object storageLock = new Object();
-    private StorageFactoryProvider storageFactoryProvider;
-    private Storage storage;
-    private Gson gson;
-    private CommonPaths paths;
-    private ConfigurationFinder finder;
-
-    public static final String STORAGE_ENDPOINT = "storage.endpoint";
-    public static final String STORAGE_CLASS = "storage.class";
-    
-    // read-only set of all known statement descriptors we trust and allow
-    private Set<String> knownStatementDescriptors;
-    // read-only set of all known categories which we allow to get registered.
-    private Set<String> knownCategoryNames;
-    // the principal callback used for retrieving the JAAS user principal
-    private PrincipalCallback principalCallback;
-    // a registry for timers which starts/stops registered timers on init()
-    // destroy()
-    private TimerRegistry timerRegistry;
-    
-    public WebStorageEndPoint() {
-        // this ugliness allows for both unit tests to inject mocks and "integration" tests to inject fake values
-        this.storageFactoryProvider = new StorageFactoryProvider() {
-            @Override
-            public StorageFactory createStorageFactory() {
-                return new StorageFactory() {
-                    @Override
-                    public Storage getStorage(String storageClass, String storageEndpoint, CommonPaths paths, StorageCredentials creds) {
-                        return StorageFactoryImpl.getStorage(storageClass, storageEndpoint, paths, creds);
-                    }
-                };
-            }
-        };
-    }
-    
-    // Package private for testing
-    WebStorageEndPoint(TimerRegistry timerRegistry, CommonPaths paths, ConfigurationFinder finder,
-                       StorageFactoryProvider storageFactoryProvider) {
-        this.timerRegistry = timerRegistry;
-        this.paths = paths;
-        this.finder = finder;
-        this.storageFactoryProvider = storageFactoryProvider;
-    }
-
-    @Override
-    public void init(ServletConfig config) throws ServletException {
-        super.init(config);
-        logger.log(Level.INFO, "Initializing web service");
-        
-        // check if thermostat home is set and readable
-        // Side effect: sets this.paths
-        sanityCheckNecessaryFiles();
-        
-        gson = new GsonBuilder()
-                .registerTypeAdapterFactory(new PojoTypeAdapterFactory())
-                .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory())
-                .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory())
-                .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory())
-                .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory())
-                .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory())
-                .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory())
-                .create();
-        
-        // Set the set of statement descriptors which we trust
-        KnownDescriptorRegistry descRegistry = KnownDescriptorRegistryFactory.getInstance();
-        knownStatementDescriptors = descRegistry.getRegisteredDescriptors();
-        // Set the set of category names which we allow to get registered
-        KnownCategoryRegistry categoryRegistry = KnownCategoryRegistryFactory.getInstance();
-        knownCategoryNames = categoryRegistry.getRegisteredCategoryNames();
-        
-        ServletContext servletContext = getServletContext();
-        
-        String serverInfo = servletContext.getServerInfo();
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(serverInfo);
-        ServletContainerInfo info = factory.getInfo();
-        PrincipalCallbackFactory cbFactory = new PrincipalCallbackFactory(info);
-        principalCallback = Objects.requireNonNull(cbFactory.getCallback());
-        
-        timerRegistry = new TimerRegistry();
-        TokenManager tokenManager = new TokenManager(timerRegistry);
-        String timeoutParam = getInitParameter(TOKEN_MANAGER_TIMEOUT_PARAM);
-        if (timeoutParam != null) {
-            tokenManager.setTimeout(Integer.parseInt(timeoutParam));
-        }
-        // The following get set as servlet context attributes in order
-        // to support clustered deployments.
-        synchronized(servletContext) {
-            servletContext.setAttribute(TOKEN_MANAGER_KEY, tokenManager);
-            servletContext.setAttribute(CATEGORY_MANAGER_KEY, new CategoryManager());
-            servletContext.setAttribute(PREPARED_STMT_MANAGER_KEY, new PreparedStatementManager());
-            servletContext.setAttribute(SERVER_TOKEN_KEY, UUID.randomUUID());
-        }
-
-        synchronized (storageLock) {
-            if (storage == null) {
-                StorageCredentials creds;
-                try {
-                    creds = getStorageCredentials();
-                } catch (IOException e) {
-                    String errorMsg = "Unable to retrieve backing storage credentials from file " + CREDENTIALS_FILE;
-                    throw new InvalidConfigurationException(errorMsg);
-                }
-                // if creds are null there is no point to continue, fail prominently.
-                if (creds == null) {
-                    String errorMsg = "No backing storage credentials file (" + CREDENTIALS_FILE + ") available";
-                    throw new InvalidConfigurationException(errorMsg);
-                }
-                String storageClass = getServletConfig().getInitParameter(STORAGE_CLASS);
-                String storageEndpoint = getServletConfig().getInitParameter(STORAGE_ENDPOINT);
-                storage = storageFactoryProvider.createStorageFactory().getStorage(storageClass, storageEndpoint, paths, creds);
-            }
-        }
-    }
-    
-    @Override
-    public void destroy() {
-        timerRegistry.shutDown();
-        synchronized (storageLock) {
-            logger.log(Level.INFO, "Going to shut down web service");
-            if (storage != null) {
-                // See IcedTea BZ#1315. Shut down storage in order
-                // to avoid further memory leaks.
-                Connection connection = storage.getConnection();
-                try {
-                    // Tests have null connections
-                    if (connection != null) {
-                        connection.disconnect();
-                    }
-                } finally {
-                    storage.shutdown();
-                }
-            }
-            logger.log(Level.INFO, "Web service shut down finished");
-        }
-    }
-
-    @Override
-    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
-        String uri = req.getRequestURI();
-        int lastPartIdx = uri.lastIndexOf("/");
-        String cmd = uri.substring(lastPartIdx + 1);
-        if (cmd.equals("prepare-statement")) {
-            prepareStatement(req, resp);
-        } else if (cmd.equals("query-execute")) {
-            queryExecute(req, resp);
-        } else if (cmd.equals("write-execute")) {
-            writeExecute(req, resp);
-        } else if (cmd.equals("register-category")) {
-            registerCategory(req, resp);
-        } else if (cmd.equals("save-file")) {
-            saveFile(req, resp);
-        } else if (cmd.equals("load-file")) {
-            loadFile(req, resp);
-        } else if (cmd.equals("purge")) {
-            purge(req, resp);
-        } else if (cmd.equals("ping")) {
-            ping(req, resp);
-        } else if (cmd.equals("generate-token")) {
-            generateToken(req, resp);
-        } else if (cmd.equals("verify-token")) {
-            verifyToken(req, resp);
-        } else if (cmd.equals("get-more")) {
-            getMore(req, resp);
-        }
-    }
-    
-    // package private for testing
-    StorageCredentials getStorageCredentials() throws IOException {
-        File credentialsFile = finder.getConfiguration(CREDENTIALS_FILE);
-        if (credentialsFile != null) {
-            logger.log(Level.CONFIG, "Loading authentication data from " + credentialsFile);
-            return createStorageCredentials(credentialsFile);
-        } else {
-            logger.warning("Unable to read database credentials.");
-            return null;
-        }
-    }
-    
-    // package private for testing
-    StorageCredentials createStorageCredentials(File underlyingFile) {
-        return new FileStorageCredentials(underlyingFile);
-    }
-
-    // Side effect: sets this.paths
-    private void sanityCheckNecessaryFiles() {
-        if (paths == null) { // for unit tests, we inject this instance
-            try {
-                // Throws config exception if basic sanity checks for
-                // THERMOSTAT_HOME don't pass.
-                paths = new CommonPathsImpl();
-            } catch (InvalidConfigurationException e) {
-                logger.log(Level.SEVERE, e.getMessage());
-                throw new RuntimeException(e);
-            }
-        }
-
-        if (finder == null) { // for unit tests, we inject this instance
-            finder = new ConfigurationFinder(paths);
-        }
-
-        File thermostatHomeFile = getThermostatHome();
-
-        String notReadableMsg = " is not readable or does not exist!";
-        // we need to be able to read ssl config for backing storage
-        // paths got set in isThermostatHomeSet()
-        File sslProperties = new File(paths.getSystemConfigurationDirectory(), "ssl.properties");
-        if (!sslProperties.canRead()) {
-            String msg = "File " + sslProperties.getAbsolutePath() +
-                    notReadableMsg;
-            logger.log(Level.SEVERE, msg);
-            throw new RuntimeException(msg);
-        }
-        // Thermostat home looks OK and seems usable
-        logger.log(Level.FINEST, "THERMOSTAT_HOME == "
-                + thermostatHomeFile.getAbsolutePath());
-    }
-
-    private File getThermostatHome() {
-        try {
-            return paths.getSystemThermostatHome();
-        } catch (InvalidConfigurationException e) {
-            // we should have just checked if this throws any exception
-            logger.log(Level.SEVERE, "Illegal configuration!", e);
-            return null;
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    @WebStoragePathHandler( path = "prepare-statement" )
-    private <T extends Pojo> void prepareStatement(HttpServletRequest req,
-            HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.PREPARE_STATEMENT)) {
-            return;
-        }
-        String queryDescrParam = req.getParameter("query-descriptor");
-        String categoryIdParam = req.getParameter("category-id");
-        SharedStateId catId = gson.fromJson(URLDecoder.decode(categoryIdParam, "UTF-8"), SharedStateId.class);
-        // Check if server token of the given category id is still valid. If it is
-        // different it means that the server has been reloaded/redeployed
-        // while the client remained up. Of course, it does not rule out a
-        // malicious client which sends a bad token on purpose. In either case
-        // it should be OK to solely send back a distinct error code indicating
-        // this situation.
-        final UUID serverToken = getServerToken();
-        if (!serverToken.equals(catId.getServerToken())) {
-            logger.log(Level.INFO, "Server token: '" + serverToken +
-                    "' and client token '" + catId.getServerToken() +
-                    "' out of sync.");
-            WebPreparedStatementResponse response = new WebPreparedStatementResponse();
-            SharedStateId id = new SharedStateId(WebPreparedStatementResponse.CATEGORY_OUT_OF_SYNC, serverToken);
-            response.setStatementId(id);
-            writeResponse(resp, response, WebPreparedStatementResponse.class);
-            return;
-        } else {
-            CategoryManager catManager = getCategoryManager();
-            Category<T> cat = (Category<T>)catManager.getCategory(catId);
-            WebPreparedStatementResponse response = new WebPreparedStatementResponse();
-            if (cat == null) {
-                // bad category? we refuse to accept this
-                logger.log(Level.WARNING, "Attepted to prepare a statement with an illegal category id: '" + 
-                                          catId + "'. server token was: '" + serverToken + "'");
-                SharedStateId id = new SharedStateId(WebPreparedStatementResponse.ILLEGAL_STATEMENT, serverToken);
-                response.setStatementId(id);
-                writeResponse(resp, response, WebPreparedStatementResponse.class);
-                return;
-            }
-            StatementDescriptor<T> desc = new StatementDescriptor<>(cat, queryDescrParam);
-            // Check if descriptor is trusted (i.e. known)
-            if (!knownStatementDescriptors.contains(desc.getDescriptor())) {
-                String msg = "Attempted to prepare a statement descriptor which we " +
-                		"don't trust! Descriptor was: ->" + desc.getDescriptor() + "<-";
-                logger.log(Level.WARNING, msg);
-                SharedStateId id = new SharedStateId(WebPreparedStatementResponse.ILLEGAL_STATEMENT, serverToken);
-                response.setStatementId(id);
-                writeResponse(resp, response, WebPreparedStatementResponse.class);
-                return;
-            }
-            
-            PreparedStatementManager prepStmtManager = getPreparedStmtManager();
-            // see if we've prepared this query already
-            PreparedStatementHolder<T> holder = prepStmtManager.getStatementHolder(desc);
-            if (holder != null) {
-                ParsedStatement<T> parsed = holder.getStmt().getParsedStatement();
-                int freeVars = parsed.getNumParams();
-                response.setNumFreeVariables(freeVars);
-                SharedStateId id = new SharedStateId(holder.getId().getId(), serverToken);
-                response.setStatementId(id);
-                writeResponse(resp, response, WebPreparedStatementResponse.class);
-                return;
-            } else {
-                // Prepare the target statement and track it via
-                // PreparedStatementManager
-                PreparedStatement<T> targetPreparedStatement;
-                try {
-                    synchronized (storageLock) {
-                        targetPreparedStatement = storage.prepareStatement(desc);
-                    }
-                } catch (DescriptorParsingException e) {
-                    logger.log(Level.WARNING, "Descriptor parse error!", e);
-                    SharedStateId id = new SharedStateId(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, serverToken);
-                    response.setStatementId(id);
-                    writeResponse(resp, response,
-                            WebPreparedStatementResponse.class);
-                    return;
-                }
-                SharedStateId stmtId = prepStmtManager.createAndPutHolder(
-                        serverToken, targetPreparedStatement, cat.getDataClass(),
-                        desc);
-                ParsedStatement<?> parsed = targetPreparedStatement
-                        .getParsedStatement();
-                response.setNumFreeVariables(parsed.getNumParams());
-                response.setStatementId(stmtId);
-                logger.log(Level.INFO, "Server: prepare-statement: stmt: " + desc + " got assigned id: " + stmtId.getId());
-                writeResponse(resp, response, WebPreparedStatementResponse.class);
-            }
-        }
-    }
-
-    @WebStoragePathHandler( path = "ping" )
-    private void ping(HttpServletRequest req, HttpServletResponse resp) {
-        if (! isAuthorized(req, resp, Roles.LOGIN)) {
-            return;
-        }
-        
-        resp.setStatus(HttpServletResponse.SC_OK);
-    }
-
-    @WebStoragePathHandler( path = "purge" )
-    private void purge(HttpServletRequest req, HttpServletResponse resp) {
-        if (! isAuthorized(req, resp, Roles.PURGE)) {
-            return;
-        }
-        
-        String agentId = req.getParameter("agentId");
-        synchronized (storageLock) {
-            storage.purge(agentId);
-        }
-        resp.setStatus(HttpServletResponse.SC_OK);
-    }
-
-    @WebStoragePathHandler( path = "load-file" )
-    private void loadFile(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.LOAD_FILE)) {
-            return;
-        }
-        
-        String name = req.getParameter("file");
-        if (! isAllowedToLoadFile(req, resp, name)) {
-            return;
-        }
-        synchronized (storageLock) {
-            try (InputStream data = storage.loadFile(name)) {
-                if (data == null) {
-                    resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
-                    return;
-                }
-                OutputStream out = resp.getOutputStream();
-                byte[] buffer = new byte[512];
-                int read = 0;
-                while (read >= 0) {
-                    read = data.read(buffer);
-                    if (read > 0) {
-                        out.write(buffer, 0, read);
-                    }
-                }
-                resp.setStatus(HttpServletResponse.SC_OK);
-            }
-        }
-    }
-
-    @WebStoragePathHandler( path = "save-file" )
-    private void saveFile(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        if (! isAuthorized(req, resp, Roles.SAVE_FILE)) {
-            return;
-        }
-        
-        boolean isMultipart = ServletFileUpload.isMultipartContent(req);
-        if (! isMultipart) {
-            throw new ServletException("expected multipart message");
-        }
-        FileItemFactory factory = new DiskFileItemFactory();
-        ServletFileUpload upload = new ServletFileUpload(factory);
-        try {
-            @SuppressWarnings("unchecked")
-            List<FileItem> items = upload.parseRequest(req);
-            for (FileItem item : items) {
-                String fieldName = item.getFieldName();
-                if (fieldName.equals("file")) {
-                    String name = item.getName();
-                    if (! isAllowedToSaveFile(req, resp, name)) {
-                        return;
-                    }
-                    InputStream in = item.getInputStream();
-                    synchronized (storageLock) {
-                        storage.saveFile(name, in, new CloseOnSave(in));
-                    }
-                }
-            }
-        } catch (FileUploadException ex) {
-            throw new ServletException(ex);
-        }
-        
-    }
-
-    private boolean isAllowedToLoadFile(HttpServletRequest req,
-            HttpServletResponse resp, String filename) {
-        String fileRole = FILES_READ_GRANT_ROLE_PREFIX + filename;
-        return isAllowed(req, resp, filename, Roles.GRANT_FILES_READ_ALL, fileRole);
-        
-    }
-
-    private boolean isAllowedToSaveFile(HttpServletRequest req,
-            HttpServletResponse resp, String filename) {
-        String fileRole = FILES_WRITE_GRANT_ROLE_PREFIX + filename;
-        return isAllowed(req, resp, filename, Roles.GRANT_FILES_WRITE_ALL, fileRole);
-    }
-
-    private boolean isAllowed(HttpServletRequest req, HttpServletResponse resp,
-            String filename, String grantAllRole, String specificFileRole) {
-        if (req.isUserInRole(grantAllRole) || req.isUserInRole(specificFileRole)) {
-            return true;
-        } else {
-            String detailMsg = "User '" + req.getRemoteUser() +
-                    "' does not belong to any of the following roles: [ " + 
-                    grantAllRole + ", " + 
-                    specificFileRole + " ]";
-            logger.log(Level.INFO, "Permission denied for file '" +
-                    filename + "'. " + detailMsg);
-            resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
-            return false;
-        }
-    }
-
-    @SuppressWarnings("unchecked") // we adapt categories in an unchecked fashion
-    @WebStoragePathHandler( path = "register-category" )
-    private synchronized void registerCategory(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.REGISTER_CATEGORY)) {
-            return;
-        }
-        String categoryName = req.getParameter("name");
-        String dataClassName = req.getParameter("data-class");
-        String categoryParam = req.getParameter("category");
-        CategoryIdentifier catIdentifier = new CategoryIdentifier(categoryName, dataClassName);
-        CategoryManager catManager = getCategoryManager();
-        SharedStateId id = catManager.getCategoryId(catIdentifier);
-        if (id == null) {
-            Class<?> dataClass = getDataClassFromName(dataClassName);
-            Category<?> category = null;
-            boolean isAggregateCat = false;
-            if ((AggregateResult.class.isAssignableFrom(dataClass))) {
-                // Aggregate category case
-                Category<?> original = Categories.getByName(categoryName);
-                if (original == null) {
-                    // DAOs register categories when they are constructed. If we
-                    // end up triggering this we are in deep water. An aggregate
-                    // query was attempted before the underlying category is
-                    // registered at all? Not good!
-                    throw new IllegalStateException("Original category of aggregate not registered!");
-                }
-                // Adapt the original category to the one we want
-                @SuppressWarnings({ "rawtypes" })
-                CategoryAdapter adapter = new CategoryAdapter(original);
-                category = adapter.getAdapted(dataClass);
-                isAggregateCat = true;
-            } else {
-                // Regular, non-aggregate category. Those categories we actually
-                // need to register with backing storage.
-                //
-                // Make sure we only register known categories
-                if (! knownCategoryNames.contains(categoryName)) {
-                    logger.log(Level.WARNING,
-                        "Attempt to register category which we don't know of! Name was '"
-                                + categoryName + "'");
-                    resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
-                    return;
-                }
-                // The following has the side effect of registering the newly
-                // deserialized Category in the Categories class.
-                category = gson.fromJson(categoryParam, Category.class);
-                synchronized (storageLock) {
-                    storage.registerCategory(category);
-                }
-            }
-            id = catManager.putCategory(getServerToken(), category, catIdentifier);
-            if (isAggregateCat) {
-                logger.log(Level.FINEST, "(id: " + id.getId() + ") did not register aggregate category " + category );
-            } else {
-                logger.log(Level.FINEST, "(id: " + id.getId() + ") registered non-aggreate category: " + category);
-            }
-        }
-        resp.setStatus(HttpServletResponse.SC_OK);
-        resp.setContentType(RESPONSE_JSON_CONTENT_TYPE);
-        writeResponse(resp, id, SharedStateId.class);
-    }
-    
-    private Class<?> getDataClassFromName(String dataClassName) {
-        try {
-            Class<?> clazz = Class.forName(dataClassName);
-            return clazz;
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Unknown data class: '" + dataClassName + "'");
-        }
-    }
-
-    /**
-     * Handler for query executions (except for getting more results). See
-     * {@link #getMore(HttpServletRequest, HttpServletResponse)}.
-     * 
-     * @param req
-     * @param resp
-     * @throws IOException
-     */
-    @WebStoragePathHandler( path = "query-execute" )
-    private <T extends Pojo> void queryExecute(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.READ)) {
-            return;
-        }
-        String queryParam = req.getParameter("prepared-stmt");
-        @SuppressWarnings("unchecked")
-        WebPreparedStatement<T> stmt = gson.fromJson(queryParam, WebPreparedStatement.class);
-        
-        // Check if the server token the client knows about still matches.
-        // Bail out early otherwise.
-        SharedStateId stmtId = stmt.getStatementId();
-        final UUID serverToken = getServerToken();
-        if (!serverToken.equals(stmtId.getServerToken())) {
-            logger.log(Level.INFO, "Server token: '" + serverToken +
-                                   "' and client token '" + stmtId.getServerToken() +
-                                   "' out of sync.");
-            WebQueryResponse<T> response = new WebQueryResponse<>();
-            response.setResponseCode(PreparedStatementResponseCode.PREP_STMT_BAD_STOKEN);
-            writeResponse(resp, response, WebQueryResponse.class);
-            return;
-        }
-        PreparedParameters p = stmt.getParams();
-        PreparedParameter[] params = p.getParams();
-        PreparedStatementManager prepStmtManager = getPreparedStmtManager();
-        PreparedStatementHolder<T> targetStmtHolder = prepStmtManager.getStatementHolder(stmtId);
-        PreparedStatement<T> targetStmt = targetStmtHolder.getStmt();
-        ParsedStatement<T> parsed = targetStmt.getParsedStatement();
-        Query<T> targetQuery = null;
-        WebQueryResponse<T> response = new WebQueryResponse<>();
-        try {
-            targetQuery = (Query<T>)parsed.patchStatement(params);
-            response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS);
-        } catch (IllegalPatchException e) {
-            logger.log(Level.INFO, "Failed to execute query", e);
-            response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH);
-            writeResponse(resp, response, WebQueryResponse.class);
-            return;
-        }
-        
-        StatementDescriptor<T> desc = targetStmtHolder.getStatementDescriptor();
-        
-        UserPrincipal userPrincipal = getUserPrincipal(req);
-        targetQuery = getQueryForPrincipal(userPrincipal, targetQuery, desc);
-        Cursor<T> cursor = targetQuery.execute();
-        List<T> resultsList = null;
-        resultsList = getBatchFromCursor(cursor, DEFAULT_QUERY_BATCH_SIZE);
-        assert(resultsList.size() <= DEFAULT_QUERY_BATCH_SIZE);
-        CursorManager cursorManager = null;
-        HttpSession userSession = req.getSession();
-        synchronized(userSession) {
-            cursorManager = (CursorManager)userSession.getAttribute(CURSOR_MANAGER_KEY);
-            if (cursorManager == null) {
-                // Not yet set for this user, create a new cursor manager
-                // and start the sweeper timer so as to prevent memory
-                // leaks due to cursors kept as a reference in cursor manager
-                cursorManager = new CursorManager(timerRegistry);
-                cursorManager.startSweeperTimer();
-                userSession.setAttribute(CURSOR_MANAGER_KEY, cursorManager);
-            }
-        }
-        // Only record cursor if there are more results to return than the
-        // first batch size.
-        int cursorId = cursorManager.put(cursor);
-        response.setCursorId(cursorId);
-        response.setHasMoreBatches(cursor.hasNext());
-        writeQueryResponse(resp, response, resultsList, targetStmtHolder);
-    }
-    
-    // package-private for testing
-    @SuppressWarnings("unchecked")
-    <T> T getServletContextAttribute(final String attributeName) {
-        ServletContext servletContext = getServletContext();
-        T attributeVal = null;
-        synchronized(servletContext) {
-            attributeVal = (T)servletContext.getAttribute(attributeName);
-        }
-        // If this throws a NPE this is certainly a bug.
-        return Objects.requireNonNull(attributeVal);
-    }
-    
-    private UUID getServerToken() {
-        return getServletContextAttribute(SERVER_TOKEN_KEY);
-    }
-    
-    private CategoryManager getCategoryManager() {
-        return getServletContextAttribute(CATEGORY_MANAGER_KEY);
-    }
-
-    private PreparedStatementManager getPreparedStmtManager() {
-        return getServletContextAttribute(PREPARED_STMT_MANAGER_KEY);
-    }
-    
-    private <T extends Pojo> void writeQueryResponse(HttpServletResponse resp, WebQueryResponse<T> response, List<T> resultsList, PreparedStatementHolder<T> targetStmtHolder) throws IOException {
-        @SuppressWarnings("unchecked")
-        T[] results = (T[])Array.newInstance(targetStmtHolder.getDataClass(), resultsList.size());
-        for (int i = 0; i < resultsList.size(); i++) {
-            results[i] = resultsList.get(i);
-        }
-        response.setResultList(results);
-        writeResponse(resp, response, WebQueryResponse.class);
-    }
-    
-    /**
-     * Handler for getting more results for a query. Queries return results
-     * in batches. The first batch is returned via {@link #queryExecute(HttpServletRequest, HttpServletResponse)}. Subsequent results will get returned using
-     * this path.
-     * 
-     * @param req
-     * @param resp
-     * @throws IOException
-     */
-    @WebStoragePathHandler( path = "get-more" )
-    private <T extends Pojo> void getMore(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.READ)) {
-            return;
-        }
-        String stmtIdParam = req.getParameter("prepared-stmt-id");
-        String cursorIdParam = req.getParameter("cursor-id");
-        String batchSizeParam = req.getParameter("batch-size");
-        
-        // Statement Id is JSON encoded.
-        SharedStateId id = gson.fromJson(URLDecoder.decode(stmtIdParam, "UTF-8"), SharedStateId.class);
-        int cursorId = Integer.parseInt(cursorIdParam);
-        int batchSize = Integer.parseInt(batchSizeParam);
-        
-        HttpSession userSession = req.getSession();
-        CursorManager cursorManager = null; 
-        synchronized(userSession) {
-            cursorManager = (CursorManager)userSession.getAttribute(CURSOR_MANAGER_KEY);
-        }
-        if (cursorManager == null) {
-            // Trying to get a cursorManager for a user which does not
-            // have it in the session as an attribute? Perhaps a cluster
-            // deployment problem?
-            throw new IllegalStateException("[get-more] No cursor manager available in session for " + req.getRemoteUser());
-        }
-        @SuppressWarnings("unchecked")
-        Cursor<T> batchCursor = (Cursor<T>)cursorManager.get(cursorId);
-        
-        PreparedStatementManager prepStmtManager = getPreparedStmtManager();
-        PreparedStatementHolder<T> targetStmtHolder = prepStmtManager.getStatementHolder(id);
-        if (batchCursor == null) {
-            // This either means:
-            // 1. The underlying (backing-storage) cursor didn't have
-            //    more results, thus WebQueryResponse.hasMoreBatches() == false,
-            //    when queryExecute() returned its WebQueryResponse. Still,
-            //    the client requested more elements anyway and ended up here.
-            //    That's really a bug in the client which performed this request.
-            // 2. The cursor expired via the sweeper timer in CursorManager,
-            //    before the client actually managed to request more results. In
-            //    that case the client is advised to re-issue the query in order
-            //    to get a new cursor, since the underlying data in the DB might
-            //    have changed anyway and results returned would be surprising.
-            //    See http://docs.mongodb.org/manual/core/cursors/
-            //    (section "Cursor Isolation")
-            String msg = "No cursor found for user " +
-                            req.getRemoteUser() + " and cursor id: " + cursorId +
-                         ". Query was: " + targetStmtHolder.getStatementDescriptor();
-            logger.log(Level.WARNING, msg);
-            WebQueryResponse<T> response = new WebQueryResponse<>();
-            response.setResponseCode(PreparedStatementResponseCode.GET_MORE_NULL_CURSOR);
-            response.setHasMoreBatches(false);
-            response.setCursorId(cursorId);
-            List<T> empty = Collections.emptyList();
-            writeQueryResponse(resp, response, empty, targetStmtHolder);
-            return;
-        }
-        // Update backing storage cursor with (possibly) changed params.
-        // This will validate batchSize input
-        batchCursor.setBatchSize(batchSize);
-        
-        List<T> nextBatch = getBatchFromCursor(batchCursor, batchCursor.getBatchSize());
-        boolean stillMoreResults = batchCursor.hasNext();
-        if (stillMoreResults) {
-            // Refresh timestamp of a live cursor so that it won't expire.
-            cursorManager.updateCursorTimeStamp(cursorId);
-        } else {
-            // no more results, remove cursor
-            cursorManager.removeCursor(cursorId);
-        }
-        logger.log(Level.FINEST, "Fetched more results (" + nextBatch.size() + ") for user '" + req.getRemoteUser() + "' cursorId " + cursorId +
-                                 ". Statement: " + targetStmtHolder.getStatementDescriptor());
-        WebQueryResponse<T> response = new WebQueryResponse<>();
-        response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS);
-        response.setHasMoreBatches(stillMoreResults);
-        response.setCursorId(cursorId);
-        writeQueryResponse(resp, response, nextBatch, targetStmtHolder);
-    }
-    
-    // Fetches the first batch of results. Number of results are determined
-    // by the default batch size in AdvancedCursor
-    private <T extends Pojo> List<T> getBatchFromCursor(final Cursor<T> cursor, final int batchSize) {
-        ArrayList<T> resultList = new ArrayList<>(batchSize);
-        for (int i = 0; i < batchSize && cursor.hasNext(); i++) {
-            resultList.add(cursor.next());
-        }
-        return resultList;
-    }
-    
-    @SuppressWarnings("unchecked")
-    @WebStoragePathHandler( path = "write-execute" )
-    private <T extends Pojo> void writeExecute(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.WRITE)) {
-            return;
-        }
-        String queryParam = req.getParameter("prepared-stmt");
-        WebPreparedStatement<T> stmt = gson.fromJson(queryParam, WebPreparedStatement.class);
-        
-        // Check if the server token the client knows about still matches.
-        // Bail out early otherwise.
-        SharedStateId stmtId = stmt.getStatementId();
-        final UUID serverToken = getServerToken();
-        if (!serverToken.equals(stmtId.getServerToken())) {
-            logger.log(Level.INFO, "Server token: '" + serverToken +
-                                   "' and client token '" + stmtId.getServerToken() +
-                                   "' out of sync.");
-            writeResponse(resp, PreparedStatementResponseCode.PREP_STMT_BAD_STOKEN, int.class);
-            return;
-        }
-        PreparedParameters p = stmt.getParams();
-        PreparedParameter[] params = p.getParams();
-        PreparedStatementManager prepStmtManager = getPreparedStmtManager();
-        PreparedStatementHolder<T> targetStmtHolder = prepStmtManager.getStatementHolder(stmt.getStatementId());
-        PreparedStatement<T> targetStmt = targetStmtHolder.getStmt();
-        ParsedStatement<T> parsed = targetStmt.getParsedStatement();
-        
-        DataModifyingStatement<T> targetStatement = null;
-        try {
-            // perform the patching of the target statement.
-            targetStatement = (DataModifyingStatement<T>)parsed.patchStatement(params);
-        } catch (IllegalPatchException e) {
-            logger.log(Level.INFO, "Failed to execute write. Stmt id was: " + stmtId, e);
-            writeResponse(resp, PreparedStatementResponseCode.ILLEGAL_PATCH, int.class);
-            return;
-        }
-        
-        // executes statement
-        int response = targetStatement.apply();
-        writeResponse(resp, response, int.class);
-    }
-    
-    private UserPrincipal getUserPrincipal(HttpServletRequest req) {
-        Principal principal = req.getUserPrincipal();
-        return principalCallback.getUserPrincipal(principal);
-    }
-
-    /*
-     * Performs the heavy lifting of query filtering. It adds a where expression
-     * and uses conjunction to the original, unfilterered, query.
-     */
-    private <T extends Pojo> Query<T> getQueryForPrincipal(
-            UserPrincipal userPrincipal, Query<T> patchedQuery,
-            StatementDescriptor<T> desc) {
-        Expression whereExpression = patchedQuery.getWhereExpression();
-        FilterResult result = userPrincipal.getReadFilter(desc);
-        Expression authorizationExpression = null;
-        switch (result.getType()) {
-        case ALL: // fall-through. same as next case.
-        case QUERY_EXPRESSION:
-            authorizationExpression = result.getFilterExpression();
-            break;
-        case EMPTY:
-            return getEmptyQuery();
-        default:
-            throw new IllegalStateException("Unknown type!");
-        }
-        // Handled empty already
-        if (whereExpression == null) {
-            // no where, use auth expression only
-            if (authorizationExpression != null) {
-                patchedQuery.where(authorizationExpression);
-                return patchedQuery;
-            }
-        } else {
-            if (authorizationExpression != null) {
-                Expression andExpression = new BinaryLogicalExpression<Expression, Expression>(
-                        authorizationExpression, BinaryLogicalOperator.AND,
-                        whereExpression);
-                patchedQuery.where(andExpression);
-                return patchedQuery;
-            }
-        }
-        assert(authorizationExpression == null);
-        // nothing to tag on
-        return patchedQuery;
-    }
-
-    private void writeResponse(HttpServletResponse resp,
-            Object responseObj, Class<?> typeOfResponseObj) throws IOException {
-        String json = null;
-        try {
-            json = gson.toJson(responseObj, typeOfResponseObj);
-        } catch (Exception e) {
-            logger.log(Level.WARNING, "JSON serialization failed for " + typeOfResponseObj, e);
-            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            return;
-        }
-        resp.setStatus(HttpServletResponse.SC_OK);
-        resp.setContentType(RESPONSE_JSON_CONTENT_TYPE);
-        try (PrintWriter pw = resp.getWriter()) {
-            pw.write(json);
-        }
-        resp.flushBuffer();
-    }
-
-    @WebStoragePathHandler( path = "generate-token" )
-    private void generateToken(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        if (! isAuthorized(req, resp, Roles.CMD_CHANNEL_GENERATE) ) {
-            return;
-        }
-        TokenManager tokenManager = (TokenManager) getServletContext().getAttribute(TOKEN_MANAGER_KEY);
-        assert tokenManager != null;
-        String clientTokenParam = req.getParameter("client-token");
-        byte[] clientToken = Base64.decodeBase64(clientTokenParam);
-        String actionName = req.getParameter("action-name");
-        // Perform pre-authorization: Since it's the client user which issues
-        // generate-token we have the correct user for which we can check role
-        // membership - and, thus, determine if this action is allowed to be
-        // performed. If the action is not allowed to be performed for this user
-        // a 403 will get returned and further verify-token would also fail,
-        // since no token gets added into the map. Trustworthiness of the
-        // action name will be implicitly checked by verify-token.
-        //
-        // We authorize based on role membership of this user. I.e. in order
-        // for a ping request (action-name == "ping") to properly authorize
-        // the user needs to be a member of role 
-        // "thermostat-cmdc-grant-ping". More generally, membership of role
-        // "thermostat-cmdc-grant-<actionName>" grants the authenticated
-        // user the <actionName> command channel action.
-        String requiredRole = CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName;
-        if (! isAuthorized(req, resp, requiredRole)) {
-            return;
-        }
-        // authorization succeeded at this point
-        byte[] token = tokenManager.generateToken(clientToken, actionName);
-        resp.setContentType("application/octet-stream");
-        resp.setContentLength(token.length);
-        resp.getOutputStream().write(token);
-    }
-
-    @WebStoragePathHandler( path = "verify-token" )
-    private void verifyToken(HttpServletRequest req, HttpServletResponse resp) {
-        if (! isAuthorized(req, resp, Roles.CMD_CHANNEL_VERIFY) ) {
-            return;
-        }
-        TokenManager tokenManager = (TokenManager) getServletContext().getAttribute(TOKEN_MANAGER_KEY);
-        assert tokenManager != null;
-        String clientTokenParam = req.getParameter("client-token");
-        byte[] clientToken = Base64.decodeBase64(clientTokenParam);
-        String actionName = req.getParameter("action-name");
-        byte[] token = Base64.decodeBase64(req.getParameter("token"));
-        // Perform authentication of the request. We can't do authorization for
-        // the originating client request here, since the only user info we have
-        // in verify-token is the identity of the agent which the client asked
-        // to perform the action for. Hence looking up role membership is not
-        // what we want here in order to limit privileges of the client.
-        //
-        // Note that we achieve this by performing authorization checks during
-        // generate-token. This is something the client user initiates and hence
-        // there we have the required user information. The entire command
-        // channel interaction can only succeed if and only if generate-token
-        // AND verify-token succeeded for the same token. Thus it's OK to only
-        // verify the token here - which in would only verify successfully if
-        // generate-token worked properly as a first step.
-        boolean verified = tokenManager.verifyToken(clientToken, token, actionName);
-        if (! verified) {
-            logger.log(Level.INFO, "Command channel action " + actionName + " from remote host " +
-                                   req.getRemoteAddr() + " FAILED to authenticate!");
-            resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
-        } else {
-            logger.log(Level.FINEST, "Command channel action " + actionName + " from remote host " +
-                    req.getRemoteAddr() + " PASSED authentication.");
-            resp.setStatus(HttpServletResponse.SC_OK);
-        }
-    }
-    
-    private boolean isAuthorized(HttpServletRequest req, HttpServletResponse resp, String role) {
-        if (req.isUserInRole(role)) {
-            return true;
-        } else {
-            logger.log(Level.INFO, "Not permitting access to " + req.getPathInfo() + ". User '" + req.getRemoteUser() + "' not in role " + role);
-            resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
-            return false;
-        }
-    }
-    
-    private <T extends Pojo> Query<T> getEmptyQuery() {
-        final Query<T> empty = new Query<T>() {
-
-            @Override
-            public void where(Expression expr) {
-                // must not be called.
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void sort(Key<?> key,
-                    com.redhat.thermostat.storage.core.Query.SortDirection direction) {
-                // must not be called.
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void limit(int n) {
-                // must not be called.
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public Cursor<T> execute() {
-                return getEmptyCursor();
-            }
-
-            @Override
-            public Expression getWhereExpression() {
-                // must not be called.
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public Statement<T> getRawDuplicate() {
-                // must not be called.
-                throw new IllegalStateException();
-            }
-            
-        };
-        return empty;
-    }
-    
-    private <T extends Pojo> Cursor<T> getEmptyCursor() {
-        final Cursor<T> empty = new BasicBatchCursor<T>() {
-
-            @Override
-            public boolean hasNext() {
-                return false;
-            }
-
-            @Override
-            public T next() {
-                // must not be called.
-                throw new IllegalStateException();
-            }
-            
-        };
-        return empty;
-    }
-
-
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/AbstractFilter.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-abstract class AbstractFilter<T extends Pojo> implements StatementFilter<T> {
-
-    private static final String ALL_ROLE_NAME = "ALL";
-    protected final Set<BasicRole> userRoles;
-    
-    protected AbstractFilter(Set<BasicRole> userRoles) {
-        this.userRoles = userRoles;
-    }
-    
-    protected Set<String> getGranted(String prefix) {
-        Set<String> allowedObjectsFromRoles = new HashSet<>();
-        for (BasicRole r : userRoles) {
-            if (r.getName().startsWith(prefix)) {
-                String allowedVm = r.getName().substring(
-                        prefix.length());
-                if (!allowedVm.equals(ALL_ROLE_NAME)) {
-                    allowedObjectsFromRoles.add(allowedVm);
-                }
-            }
-        }
-        return allowedObjectsFromRoles;
-    }
-    
-    protected FilterResult allWithExpression(Expression parentExpression) {
-        if (parentExpression != null) {
-            FilterResult result = new FilterResult(
-                    ResultType.QUERY_EXPRESSION);
-            result.setFilterExpression(parentExpression);
-            return result;
-        } else {
-            return new FilterResult(ResultType.ALL);
-        }
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/AgentIdFilter.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-/**
- * Filters queries based on granted agent IDs.
- * 
- * @see Roles#GRANT_AGENTS_READ_ALL
- */
-class AgentIdFilter<T extends Pojo> extends AbstractFilter<T> {
-    
-    static final RolePrincipal GRANT_AGENTS_READ_ALL = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL);
-    static final String AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX = "thermostat-agents-grant-read-agentId-";
-    
-    AgentIdFilter(Set<BasicRole> userRoles) {
-        super(userRoles);
-    }
-
-    @Override
-    public FilterResult applyFilter(StatementDescriptor<T> desc,
-                                    Expression parentExpression) {
-        if (userRoles.contains(GRANT_AGENTS_READ_ALL)) {
-            return allWithExpression(parentExpression);
-        }
-        Category<T> category = desc.getCategory();
-        // user cannot read all agents
-        if (category.getKey(Key.AGENT_ID.getName()) != null) {
-            // tag on in clause for agentId
-            ExpressionFactory factory = new ExpressionFactory();
-            Set<String> agentIds = getGrantedAgentsByAgentId();
-            Expression filterExpression = factory.in(Key.AGENT_ID, agentIds, String.class);
-            FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION);
-            if (parentExpression != null) {
-                filterExpression = factory.and(parentExpression, filterExpression);
-            }
-            result.setFilterExpression(filterExpression);
-            return result;
-        } else {
-            // can't do anything here, let it through for next stage.
-            return allWithExpression(parentExpression);
-        }
-    }
-
-    private Set<String> getGrantedAgentsByAgentId() {
-        return getGranted(AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX);
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/BasicRole.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.io.Serializable;
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Objects;
-
-/**
- * Base class for all thermostat roles.
- * 
- * To be precise, every {@link Principal} which does NOT have the same name
- * as the currently logged in user, are BasicRole principals. The name of a
- * Principal is defined by {@link Principal#getName()}.
- *
- */
-public abstract class BasicRole implements Group, Serializable {
-    
-    private static final long serialVersionUID = -4572772782292794645L;
-    protected String name;
-    
-    public BasicRole(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Compares two BasicRoles.
-     * 
-     * @return true if and only if other is a BasicRole and its name is the same
-     *         as this role.
-     */
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof BasicRole)) {
-            return false;
-        }
-        String otherName = ((Principal) other).getName();
-        return Objects.equals(name, otherName);
-    }
-    
-    @Override
-    public int hashCode() {
-        return (name == null ? 0 : name.hashCode());
-    }
-    
-    @Override
-    public String getName() {
-        return name;
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallback.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.security.Principal;
-
-/**
- * Default callback which simply casts the given principal.
- *
- */
-final class DefaultPrincipalCallback implements PrincipalCallback {
-
-    @Override
-    public UserPrincipal getUserPrincipal(Principal principal) {
-        // Since we use our own JAAS based auth module this cast is safe for
-        // Tomcat and JBoss AS 7/wildfly since they allow for configuration of
-        // user principal classes. 
-        return (UserPrincipal)principal;
-    }
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/FilterResult.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import com.redhat.thermostat.storage.query.Expression;
-
-public class FilterResult {
-
-    public enum ResultType {
-        /** Statement would return an empty result */
-        EMPTY,
-        /** Statement can go through unfiltered */
-        ALL,
-        /** Statement needs to be filtered with the given expression */
-        QUERY_EXPRESSION
-    }
-    
-    private final ResultType type;
-    private Expression filterExpression;
-    
-    FilterResult(ResultType type) {
-        this.type = type;
-    }
-
-    public Expression getFilterExpression() {
-        return filterExpression;
-    }
-
-    void setFilterExpression(Expression filterExpression) {
-        if (type != ResultType.QUERY_EXPRESSION) {
-            throw new IllegalStateException("Only query expression return type can have filter expression set");
-        }
-        this.filterExpression = filterExpression;
-    }
-
-    public ResultType getType() {
-        return type;
-    }
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/HostnameFilter.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-/**
- * 
- * Filters based on granted host names.
- * 
- * @see Roles#GRANT_HOSTS_READ_ALL
- */
-class HostnameFilter<T extends Pojo> extends AbstractFilter<T> {
-    
-    static final RolePrincipal GRANT_HOSTS_READ_ALL = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL);
-    static final String HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX = "thermostat-hosts-grant-read-hostname-";
-    
-    HostnameFilter(Set<BasicRole> userRoles) {
-        super(userRoles);
-    }
-
-    @Override
-    public FilterResult applyFilter(StatementDescriptor<T> desc,
-            Expression parentExpression) {
-        if (userRoles.contains(GRANT_HOSTS_READ_ALL)) {
-            return allWithExpression(parentExpression);
-        }
-        // not all hosts are allowed
-        if (desc.getCategory().equals(HostInfoDAO.hostInfoCategory)) {
-            // add a hostname query expression
-            ExpressionFactory factory = new ExpressionFactory();
-            Set<String> hostnames = getGrantedHostsByHostname();
-            Expression filterExpression = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class);
-            FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION);
-            if (parentExpression != null) {
-                filterExpression = factory.and(parentExpression, filterExpression);
-            }
-            result.setFilterExpression(filterExpression);
-            return result;
-        } else {
-            // can't do anything
-            return allWithExpression(parentExpression);
-        }
-    }
-
-    private Set<String> getGrantedHostsByHostname() {
-        return getGranted(HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX);
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallback.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.security.Principal;
-import java.util.Objects;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.security.auth.Subject;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.web.server.containers.ContainerVersion;
-import com.redhat.thermostat.web.server.containers.ServletContainerInfo;
-
-/**
- * Principal callback for the jetty container.
- *
- */
-class JettyPrincipalCallback implements PrincipalCallback {
-    
-    private static final String JETTY8_JAAS_USER_PRINCIPAL_CLASS_NAME = "org.eclipse.jetty.plus.jaas.JAASUserPrincipal";
-    private static final String JETTY9_JAAS_USER_PRINCIPAL_CLASS_NAME = "org.eclipse.jetty.jaas.JAASUserPrincipal";
-    
-    private static final Logger logger = LoggingUtils.getLogger(JettyPrincipalCallback.class);
-    private final ServletContainerInfo info;
-    
-    JettyPrincipalCallback(ServletContainerInfo info) {
-        this.info = Objects.requireNonNull(info);
-    }
-    
-    @Override
-    public UserPrincipal getUserPrincipal(Principal principal) {
-        Subject subject = getJettySubject(principal);
-        Set<UserPrincipal> userPrincipals = subject.getPrincipals(UserPrincipal.class);
-        if (userPrincipals.size() != 1) {
-            throw new IllegalStateException("Number of thermostat user principals must be exactly 1!");
-        }
-        return userPrincipals.iterator().next();
-    }
-    
-    private Subject getJettySubject(Principal principal) {
-        ContainerVersion version = info.getContainerVersion();
-        // Jetty has our principal on the accessible subject.
-        // The package of the JAASUserPrincipal class changed between
-        // Jetty 8 and Jetty 9.
-        if (version.getMajor() <= 8) {
-            return getSubjectFromClass(principal, JETTY8_JAAS_USER_PRINCIPAL_CLASS_NAME);
-        } else {
-            // >= 9 and go with jetty 9's name
-            return getSubjectFromClass(principal, JETTY9_JAAS_USER_PRINCIPAL_CLASS_NAME);
-        }
-    }
-    
-    private Subject getSubjectFromClass(Principal principal, String clazzName) {
-        Subject subject = null;
-        try {
-            // Do this via reflection in order to avoid a hard dependency
-            // on jetty-plus.
-            Class<?> jassUserPrincipal = Class.forName(clazzName);
-            Method method = jassUserPrincipal.getDeclaredMethod("getSubject");
-            subject = (Subject)method.invoke(principal);
-        } catch (ClassNotFoundException | NoSuchMethodException
-                | SecurityException | IllegalAccessException
-                | IllegalArgumentException | InvocationTargetException e) {
-            // log and continue
-            logger.log(Level.WARNING, e.getMessage(), e);
-        }
-        if (subject == null) {
-            throw new IllegalStateException(
-                    "Could not retrieve subject from principal of type "
-                            + principal.getClass().getName());
-        }
-        return subject;
-    }
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallback.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.security.Principal;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * 
- * Callback for retrieving the {@link UserPrincipal} from the generic
- * {@link Principal} returned by {@link HttpServletRequest#getUserPrincipal()}.
- * 
- * In general, there should be one implementation per supported servlet
- * container.
- *
- */
-public interface PrincipalCallback {
-
-    /**
-     * 
-     * @param principal The principal as returned by {@link HttpServletRequest#getUserPrincipal()}.
-     * @return Thermostat's matching {@link UserPrincipal}.
-     */
-    UserPrincipal getUserPrincipal(Principal principal);
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactory.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import com.redhat.thermostat.web.server.containers.ContainerName;
-import com.redhat.thermostat.web.server.containers.ServletContainerInfo;
-
-/**
- * Factory producing a {@link PrincipalCallback}.
- *
- */
-public class PrincipalCallbackFactory {
-    
-    private final ServletContainerInfo info;
-    
-    public PrincipalCallbackFactory(ServletContainerInfo info) {
-        this.info = info;
-    }
-
-    public PrincipalCallback getCallback() {
-        // info may be null. in this case return the default callback
-        if (info == null) {
-            return new DefaultPrincipalCallback();
-        }
-        ContainerName name = info.getName();
-        switch(name) {
-        case JETTY: 
-            return new JettyPrincipalCallback(info);
-        default:
-            // includes tomcat and wildfly/JBoss AS
-            return new DefaultPrincipalCallback();
-        }
-    }
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/RolePrincipal.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.Vector;
-
-import static com.redhat.thermostat.common.utils.IteratorUtils.asList;
-
-/**
- * Class representing a simple thermostat role. Roles can be nested.
- * 
- * @see Group
- */
-public class RolePrincipal extends BasicRole {
-
-    private static final long serialVersionUID = -7366668253791828610L;
-    // the set of nested roles if any
-    private final HashSet<Group> roles = new HashSet<>();
-
-    /**
-     * Creates a role principal with the specified role name containing no roles
-     * within it.
-     * 
-     * @param roleName
-     * @throws NullPointerException if roleName was null.
-     */
-    public RolePrincipal(String roleName) {
-        super(Objects.requireNonNull(roleName));
-    }
-
-    /**
-     * Adds a role this role principal.
-     * 
-     * @return true if and only if the role has been successfully added.
-     * @throws IllegalArgumentException
-     *             if the principal to be added is not a {@link Group}
-     *         NullPointerException If the role was null.
-     */
-    @Override
-    public boolean addMember(Principal role) {
-        if (!(Objects.requireNonNull(role) instanceof Group)) {
-            throw new IllegalArgumentException("principal not a group");
-        }
-        return roles.add((Group) role);
-    }
-
-    /**
-     * Removes a role from this role principal.
-     * 
-     * @return true if the principal was successfully removed.
-     */
-    @Override
-    public boolean removeMember(Principal role) {
-        // will return false if role not a member, omit check for Group
-        return roles.remove(role);
-    }
-
-    @Override
-    public boolean isMember(Principal member) {
-        if (roles.contains(member)) {
-            return true;
-        }
-        // recursive case
-        boolean isMember = false;
-        for (Group group : roles) {
-            isMember = isMember || group.isMember(member);
-            if (!isMember) {
-                break;
-            }
-        }
-        return isMember;
-    }
-
-    @Override
-    public Enumeration<? extends Principal> members() {
-        Vector<Principal> vector = new Vector<>();
-        for (Group group : roles) {
-            vector.add(group);
-        }
-        return vector.elements();
-    }
-
-}
\ No newline at end of file
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-/**
- * Roles thermostat knows about.
- *
- */
-public interface Roles {
-    
-    /**
-     * Allows for a user to read records tied to any host.
-     */
-    final String GRANT_HOSTS_READ_ALL = "thermostat-hosts-grant-read-hostname-ALL";
-    /**
-     * Allows for a user to read records tied to any JVM id.
-     */
-    final String GRANT_VMS_READ_BY_VM_ID_ALL = "thermostat-vms-grant-read-vmId-ALL";
-    /**
-     * Allows for a user to read records tied to any username the JVM is running as.
-     */
-    final String GRANT_VMS_READ_BY_USERNAME_ALL = "thermostat-vms-grant-read-username-ALL";
-    /**
-     * Allows for a user to read any file from storage.
-     */
-    final String GRANT_FILES_READ_ALL = "thermostat-files-grant-read-filename-ALL";
-    /**
-     * Allows for a user to write any file to storage.
-     */
-    final String GRANT_FILES_WRITE_ALL = "thermostat-files-grant-write-filename-ALL";
-    /**
-     * Allows for a user to see records tied to any agent.
-     */
-    final String GRANT_AGENTS_READ_ALL = "thermostat-agents-grant-read-agentId-ALL";
-    /**
-     * Allows for a user to read all records. No restrictions are
-     * performed on as to what this user can see.
-     */
-    final String GRANT_READ_ALL = "thermostat-grant-read-ALL";
-
-    /*
-     * TODO: Not sure if we still want to use the following 4 stop-gap roles. 
-     */
-    final String APPEND = "thermostat-add";
-    final String REPLACE = "thermostat-replace";
-    final String UPDATE = "thermostat-update";
-    final String DELETE = "thermostat-remove";
-    
-    final String PREPARE_STATEMENT = "thermostat-prepare-statement";
-    final String READ = "thermostat-query";
-    final String WRITE = "thermostat-write";
-    final String LOAD_FILE = "thermostat-load-file";
-    final String SAVE_FILE = "thermostat-save-file";
-    final String PURGE = "thermostat-purge";
-    final String REGISTER_CATEGORY = "thermostat-register-category";
-    final String CMD_CHANNEL_VERIFY = "thermostat-cmdc-verify";
-    final String CMD_CHANNEL_GENERATE = "thermostat-cmdc-generate";
-    final String LOGIN = "thermostat-login";
-    final String ACCESS_REALM = "thermostat-realm";
-    
-    final String[] ALL_ROLES = { APPEND, REPLACE, UPDATE, DELETE, READ,
-            LOAD_FILE, SAVE_FILE, PURGE, REGISTER_CATEGORY,
-            CMD_CHANNEL_GENERATE, CMD_CHANNEL_VERIFY, LOGIN, ACCESS_REALM,
-            PREPARE_STATEMENT, GRANT_AGENTS_READ_ALL, GRANT_HOSTS_READ_ALL,
-            GRANT_VMS_READ_BY_USERNAME_ALL, GRANT_VMS_READ_BY_VM_ID_ALL,
-            GRANT_READ_ALL };
-    
-    final String[] AGENT_ROLES = {
-            APPEND, REPLACE, UPDATE, DELETE, SAVE_FILE, PURGE,
-            REGISTER_CATEGORY, CMD_CHANNEL_VERIFY,
-            LOGIN, ACCESS_REALM
-    };
-    
-    final String[] CLIENT_ROLES = {
-            ACCESS_REALM, LOGIN, CMD_CHANNEL_GENERATE, LOAD_FILE,
-            READ, REGISTER_CATEGORY, PREPARE_STATEMENT
-    };
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/StatementFilter.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-
-/**
- * A filter suitable to get applied to {@link PreparedStatement}s before they
- * are executed.
- *
- */
-interface StatementFilter<T extends Pojo> {
-
-    /**
-     * Applies this filter. Note that filters may be chained.
-     * 
-     * @param desc
-     *            The statement descriptor to apply the filter to.
-     * @param parentExpression
-     *            The Expression as constructed by the previous Filter. May be
-     *            null.
-     * @return A filtered result with the Expression set to use for filtering if
-     *         result type was QUERY_EXPRESSION.
-     */
-    FilterResult applyFilter(StatementDescriptor<T> desc,
-            Expression parentExpression);
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.io.Serializable;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-/**
- * Class representing thermostat users
- *
- */
-public class UserPrincipal implements Serializable, Principal {
-    
-    private static final RolePrincipal GRANT_READ_ALL = new RolePrincipal(Roles.GRANT_READ_ALL);
-    
-    private static final long serialVersionUID = 2646753284881445421L;
-    // The set of roles this user is a member of (they may be nested)
-    private final Set<BasicRole> roles = new HashSet<>();
-    // The name of this principal
-    private String name;
-    
-    /**
-     * Creates a new user principal with the given name
-     * 
-     * @param name The user name.
-     * @throws NullPointerException if name is null.
-     */
-    public UserPrincipal(String name) {
-        this.name = Objects.requireNonNull(name);
-    }
-
-    /**
-     * 
-     * @return The set of roles this principal is a member of. An empty set
-     *         if this user has no role memberships.
-     */
-    public final Set<BasicRole> getRoles() {
-        return new HashSet<>(roles);
-    }
-
-    /**
-     * Sets the set of roles which this principal is a member of.
-     * 
-     * @param roles the set of roles
-     * @throws NullPointerException If the given role set was null.
-     */
-    public void setRoles(Set<BasicRole> roles) {
-        this.roles.addAll(Objects.requireNonNull(roles));
-    }
-    
-    /**
-     * Prepare a read filter for this user which can be applied prior executing
-     * trusted prepared queries.
-     * 
-     * @param desc the descriptor for which to get the filter.
-     *
-     * @return An {@link FilterResult} which can be used to make a decision on
-     *         which records to return.
-     */
-    public <T extends Pojo> FilterResult getReadFilter(StatementDescriptor<T> desc) {
-        if (getRoles().contains(GRANT_READ_ALL)) {
-            // user can see everything, no filtering is happening at all.
-            return new FilterResult(ResultType.ALL);
-        }
-        List<StatementFilter<T>> filters = buildFilters();
-        
-        // perform filtering using our list of filters
-        Expression parentExpression = null;
-        FilterResult overallResult = null;
-        for (StatementFilter<T> filter: filters) {
-            overallResult = filter.applyFilter(desc, parentExpression);
-            switch (overallResult.getType()) {
-            case ALL: // fall-through, expression == null
-            case QUERY_EXPRESSION:
-                // continue filtering
-                parentExpression = overallResult.getFilterExpression();
-                break;
-            case EMPTY:
-                // no point continuing, already nothing
-                return overallResult;
-            default:
-                throw new IllegalStateException("Unknown result type!");
-            }
-        }
-        // done filtering
-        return overallResult;
-    }
-
-    /*
-     * Filters are applied in order. Passing through one which didn't return
-     * empty continues the filter chain. Currently, we filter by:
-     * agent IDs -> hostnames -> vm IDs -> vm usernames
-     */
-    private <T extends Pojo> List<StatementFilter<T>> buildFilters() {
-        List<StatementFilter<T>> filters = new ArrayList<>();
-        Set<BasicRole> roles = getRoles();
-        AgentIdFilter<T> agentIdFilter = new AgentIdFilter<>(roles);
-        HostnameFilter<T> hostnameFilter = new HostnameFilter<>(roles);
-        VmIdFilter<T> vmIdFilter = new VmIdFilter<>(roles);
-        VmUsernameFilter<T> vmUsernameFilter = new VmUsernameFilter<>(roles);
-        filters.add(agentIdFilter);
-        filters.add(hostnameFilter);
-        filters.add(vmIdFilter);
-        filters.add(vmUsernameFilter);
-        return filters;
-    }
-    
-    @Override
-    public String getName() {
-        return name;
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof Principal)) {
-            return false;
-        }
-        String otherName = ((Principal) other).getName();
-        return Objects.equals(name, otherName);
-    }
-    
-    @Override
-    public int hashCode() {
-        return (name == null ? 0 : name.hashCode());
-    }
-    
-    @Override
-    public String toString() {
-        return this.getClass().getName() + ": " + name;
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmIdFilter.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-/**
- * Filters based on granted VM IDs.
- * 
- * @see Roles#GRANT_VMS_READ_BY_VM_ID_ALL
- */
-class VmIdFilter<T extends Pojo> extends AbstractFilter<T> {
-    
-    static final RolePrincipal GRANT_VMS_BY_ID_READ_ALL = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL);
-    static final String VMS_BY_VM_ID_GRANT_ROLE_PREFIX = "thermostat-vms-grant-read-vmId-";
-    
-    VmIdFilter(Set<BasicRole> userRoles) {
-        super(userRoles);
-    }
-
-    @Override
-    public FilterResult applyFilter(StatementDescriptor<T> desc,
-                                    Expression parentExpression) {
-        if (userRoles.contains(GRANT_VMS_BY_ID_READ_ALL)) {
-            return allWithExpression(parentExpression);
-        }
-        // perform filtering on vmId
-        Category<T> category = desc.getCategory();
-        if (category.getKey(Key.VM_ID.getName()) != null) {
-            // add vmId IN clause
-            ExpressionFactory factory = new ExpressionFactory();
-            Set<String> vmIds = getGrantedVmsByVmId();
-            Expression filterExpression = factory.in(Key.VM_ID, vmIds, String.class);
-            if (parentExpression != null) {
-                filterExpression = factory.and(parentExpression, filterExpression);
-            }
-            FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION);
-            result.setFilterExpression(filterExpression);
-            return result;
-        } else {
-            // can't do much
-            return allWithExpression(parentExpression);
-        }
-    }
-    
-    private Set<String> getGrantedVmsByVmId() {
-        return getGranted(VMS_BY_VM_ID_GRANT_ROLE_PREFIX);
-    }
-
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmUsernameFilter.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-/**
- * Filters based on the granted VM usernames. I.e. the Unix username the
- * individual VM runs as.
- * 
- * @see Roles#GRANT_VMS_READ_BY_USERNAME_ALL
- */
-class VmUsernameFilter<T extends Pojo> extends AbstractFilter<T> {
-
-    static final RolePrincipal GRANT_VMS_USERNAME_READ_ALL = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL);
-    static final String VMS_BY_USERNAME_GRANT_ROLE_PREFIX = "thermostat-vms-grant-read-username-";
-    
-    VmUsernameFilter(Set<BasicRole> userRoles) {
-        super(userRoles);
-    }
-    
-    @Override
-    public FilterResult applyFilter(StatementDescriptor<T> desc,
-                                    Expression parentExpression) {
-        if (userRoles.contains(GRANT_VMS_USERNAME_READ_ALL)) {
-            return allWithExpression(parentExpression);
-        }
-        // perform filtering on the username of the vm
-        if (desc.getCategory().equals(VmInfoDAO.vmInfoCategory)) {
-            ExpressionFactory factory = new ExpressionFactory();
-            Set<String> vmUsernames = getGrantedVmsByUsername();
-            Expression filterExpression = factory.in(VmInfoDAO.usernameKey, vmUsernames, String.class);
-            if (parentExpression != null) {
-                filterExpression = factory.and(parentExpression, filterExpression);
-            }
-            FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION);
-            result.setFilterExpression(filterExpression);
-            return result;
-        } else {
-            // can't do much
-            return allWithExpression(parentExpression);
-        }
-    }
-    
-    private Set<String> getGrantedVmsByUsername() {
-        return getGranted(VMS_BY_USERNAME_GRANT_ROLE_PREFIX);
-    }
-
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/WebStoragePathHandler.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation for web storage handler methods. This is used in order
- * to ensure proper authorization coverage.
- *
- */
-@Target( ElementType.METHOD )
-@Retention( RetentionPolicy.RUNTIME )
-public @interface WebStoragePathHandler {
-    
-    String path();
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipal.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Enumeration;
-
-/**
- * Class representing a thermostat role. It simply wraps an existing {@link Group}. 
- * 
- * @see Group
- */
-public class WrappedRolePrincipal extends BasicRole {
-
-    private static final long serialVersionUID = -3852507889428067737L;
-    // the underlying group
-    private final Group group;
-    
-    /**
-     * Creates a role which delegates to the given group.
-     * 
-     * @param group
-     */
-    public WrappedRolePrincipal(Group group) {
-        super(group.getName());
-        this.group = group;
-    }
-
-    @Override
-    public boolean addMember(Principal user) {
-        return this.group.addMember(user);
-    }
-
-    @Override
-    public boolean removeMember(Principal user) {
-        return this.group.removeMember(user);
-    }
-
-    @Override
-    public boolean isMember(Principal member) {
-        return this.group.isMember(member);
-    }
-
-    @Override
-    public Enumeration<? extends Principal> members() {
-        return this.group.members();
-    }
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModule.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-/**
- * Base class for Thermostat JAAS login modules.
- *
- */
-public abstract class AbstractLoginModule implements LoginModule {
-    
-    private static final Logger logger = LoggingUtils.getLogger(AbstractLoginModule.class);
-    protected CallbackHandler callBackHandler;
-    protected Subject subject;
-    protected boolean debug = false;
-    
-    @Override
-    public void initialize(Subject subject, CallbackHandler callbackHandler,
-            Map<String, ?> sharedState, Map<String, ?> options) {
-        this.subject = subject;
-        this.callBackHandler = callbackHandler;
-        this.debug = "true".equalsIgnoreCase((String)options.get("debug"));
-    }
-
-    /**
-     * Get username and password from the callback.
-     * 
-     * @return An array of length two where the first element is the username as
-     *         String and the second element is the password as char[].
-     * @throws LoginException
-     *             if the retrieval fails (e.g. no callback is available).
-     */
-    protected Object[] getUsernamePasswordFromCallBack() throws LoginException {
-        if (callBackHandler == null) {
-            throw new LoginException("No callback handler");
-        }
-        Object[] creds = new Object[2];
-        NameCallback nc = new NameCallback("Username: ");
-        PasswordCallback pc = new PasswordCallback("Password: ", false);
-        Callback[] callbacks = new Callback[] { nc, pc };
-        try {
-            callBackHandler.handle(callbacks);
-            creds[0] = nc.getName();
-            creds[1] = pc.getPassword();
-            pc.clearPassword();
-            return creds;
-        } catch (IOException | UnsupportedCallbackException e) {
-            logger.log(Level.FINEST, "Can't get username", e);
-            throw new LoginException(e.getMessage());
-        } 
-    }
-    
-    /**
-     * Get the user's name from the callback.
-     * 
-     * @return The user's name.
-     * @throws LoginException
-     *             if the retrieval fails (e.g. no callback is available).
-     */
-    protected String getUsernameFromCallBack() throws LoginException {
-        if (callBackHandler == null) {
-            throw new LoginException("No callback handler");
-        }
-        NameCallback nc = new NameCallback("Username: ");
-        PasswordCallback pc = new PasswordCallback("Password: ", false);
-        Callback[] callbacks = new Callback[] { nc, pc };
-        try {
-            callBackHandler.handle(callbacks);
-            return nc.getName();
-        } catch (IOException | UnsupportedCallbackException e) {
-            logger.log(Level.FINEST, "Can't get username", e);
-            throw new LoginException(e.getMessage());
-        } 
-    }
-
-    protected final void debugLog(Level level, String message) {
-        if (debug) {
-            logger.log(level, message);
-        }
-    }
-
-    protected final void debugLog(Level level, String message, Exception ex) {
-        if (debug) {
-            logger.log(level, message, ex);
-        }
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModule.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletRequest;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.web.server.auth.BasicRole;
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-import com.redhat.thermostat.web.server.auth.UserPrincipal;
-import com.redhat.thermostat.web.server.auth.WrappedRolePrincipal;
-
-/**
- * LoginModule which delegates to the configured implementing
- * {@link LoginModule}. This is useful in order to be able to provide a 
- * guarrantee that a {@link UserPrincipal} is always returned for
- * {@link HttpServletRequest#getUserPrincipal()} if any.
- * 
- */
-public final class DelegateLoginModule extends AbstractLoginModule {
-    
-    private static final Logger logger = LoggingUtils.getLogger(DelegateLoginModule.class);
-    private static final String JAAS_DELEGATE_CONFIG_NAME = "ThermostatJAASDelegate";
-    // the delegate
-    private LoginContext delegateContext;
-    private String username;
-    /**
-     * The config name to use. Defaults to {@linkplain DelegateLoginModule#JAAS_DELEGATE_CONFIG_NAME}
-     */
-    private String configName;
-    
-    /**
-     * Default, no-arg constructor.
-     */
-    public DelegateLoginModule() {
-        this.configName = JAAS_DELEGATE_CONFIG_NAME;
-    }
-    
-    // used for testing
-    DelegateLoginModule(String configName) {
-        this.configName = configName;
-    }
-    
-    
-    @Override
-    public void initialize(Subject subject, CallbackHandler callbackHandler,
-            Map<String, ?> sharedState, Map<String, ?> options) {
-        super.initialize(subject, callbackHandler, sharedState, options);
-        /*
-         * Create and initialize the delegate 
-         */
-        try {
-            this.delegateContext = new LoginContext(configName, subject, callbackHandler);
-            debugLog(Level.FINEST, "successfully created delegate login context");
-        } catch (LoginException e) {
-            // This only happens if there is no "ThermostatJAASDelegate" config
-            // and also no configuration with the name "other", which is likely
-            // always there for real application servers.
-            String message = "Fatal: Could not initialize delegate. " +
-                    "'ThermostatJAASDelegate' " +
-                    "and 'other' login modules are both not configured!";
-            logger.log(Level.SEVERE, message, e);
-            throw new RuntimeException(message);
-        }
-    }
-
-    @Override
-    public boolean login() throws LoginException {
-        try {
-            username = super.getUsernameFromCallBack();
-            delegateContext.login();
-            debugLog(Level.FINEST, "Login succeeded for " + username + " using the delegate.");
-        } catch (LoginException e) {
-            // This only shows up if debug is turned on
-            // since it's just a plain login failure.
-            debugLog(Level.FINEST, "Login failed", e);
-            throw e;
-        }
-        return true;
-    }
-
-    @Override
-    public boolean commit() throws LoginException {
-        /*
-         * Make sure to retrieve principals from the authenticated subject,
-         * wrap them in UserPrincipal/BasicRole principals and inform the
-         * UserPrincipal about the roles it is a member of.
-         */
-        Set<Principal> principals = subject.getPrincipals();
-        int size = principals.size();
-        Set<Principal> wrappedPrincipals = new HashSet<>(size);
-        // the user principal is not in the roles set
-        Set<BasicRole> roles = new HashSet<>(size -1);
-        UserPrincipal userPrincipal = null;
-        for (Principal p : principals) {
-            if (p.getName().equals(username)) {
-                // add our user principal
-                if (userPrincipal != null) {
-                    logger.log(Level.SEVERE, "Fatal: > 1 user principals!");
-                    throw new IllegalStateException("> 1 user principals!");
-                }
-                userPrincipal = new UserPrincipal(username);
-                wrappedPrincipals.add(userPrincipal);
-            } else {
-                // group (a.k.a role). It may be a simple principal or a 
-                // Group. If it is a group, we simply wrap it. If it isn't
-                // we use our simple RolePrincipal instead.
-                BasicRole role;
-                if (p instanceof Group) {
-                    role = new WrappedRolePrincipal((Group)p);
-                    wrappedPrincipals.add(role);
-                    roles.add(role);
-                } else {
-                    role = new RolePrincipal(p.getName());
-                    wrappedPrincipals.add(role);
-                    roles.add(role);
-                }
-            }
-        }
-        // Remove old principals and push the newly wrapped ones
-        principals.clear();
-        principals.addAll(wrappedPrincipals);
-        // Finally, inform the user principal about the roles it is a member of.
-        // We need this in order to be able to do something (filtering/authorization)
-        // with these roles from the web storage servlet.
-        if (userPrincipal != null) {
-            userPrincipal.setRoles(roles);
-        }
-
-        debugLog(Level.FINEST, "Committed changes for '" + username + "'");
-        return true;
-    }
-
-    @Override
-    public boolean abort() throws LoginException {
-        if (subject != null) {
-            // remove any principals
-            Set<Principal> principals = subject.getPrincipals();
-            principals.clear();
-        }
-        debugLog(Level.FINEST, "Login aborted!");
-        return true;
-    }
-
-    @Override
-    public boolean logout() throws LoginException {
-        try {
-            delegateContext.logout();
-            Set<Principal> principals = subject.getPrincipals();
-            principals.clear();
-            debugLog(Level.FINEST, "Logged out successfully!");
-            return true;
-        } catch (LoginException e) {
-            debugLog(Level.FINEST, "Logout failed!" + e.getMessage());
-            return false;
-        }
-    }
-    
-    /*
-     * Package private method in order to get at the subject
-     */
-    final Subject getSubject() {
-        return this.subject;
-    }
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Properties;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
-import com.redhat.thermostat.web.server.ConfigurationFinder;
-
-/**
- * 
- * Validates users against an internal, properties based, user database.
- *
- */
-class PropertiesUserValidator implements UserValidator {
-    
-    private static final Logger logger = LoggingUtils.getLogger(PropertiesUserValidator.class);
-    private static final String DEFAULT_USERS_FILE = "thermostat-users.properties";
-    private Properties users;
-    
-    PropertiesUserValidator() {
-        // this is the default configuration. it should be overriden through different means
-        // see javadoc of PropertiesUsernameRolesLoginModule
-        this(new ConfigurationFinder(new CommonPathsImpl()).getConfiguration(DEFAULT_USERS_FILE));
-    }
-    
-    PropertiesUserValidator(String usersFile) {
-        this(new File(usersFile));
-    }
-
-    PropertiesUserValidator(File file) {
-        loadUsers(file);
-    }
-
-    @Override
-    public synchronized void authenticate(String username, char[] password)
-            throws UserValidationException {
-        if (users == null) {
-            throw new UserValidationException("No user database");
-        }
-        String tmp = users.getProperty(username);
-        if (tmp == null) {
-            throw new UserValidationException("User '" + username + "' not found");
-        }
-        // We have an entry in our user db for the requested username.
-        char refPassWd[] = tmp.toCharArray();
-        try {
-            validate(password, refPassWd);
-        } finally {
-            // clear our password
-            for (int i = 0; i < refPassWd.length; i++) {
-                refPassWd[i] = '\0';
-            }
-        }
-    }
-    
-    private void validate(char[] theirPwd, char[] ourPwd) throws UserValidationException {
-        String failureMessage = "Login failed!";
-        if (theirPwd.length != ourPwd.length) {
-            throw new UserValidationException(failureMessage);
-        }
-        for (int i = 0; i < theirPwd.length; i++) {
-            if (theirPwd[i] != ourPwd[i]) {
-                throw new UserValidationException(failureMessage);
-            }
-        }
-    }
-
-    private void loadUsers(File userDB) {
-        if (users == null) {
-            Properties users = new Properties();
-            try (FileInputStream stream = new FileInputStream(userDB)) {
-                users.load(stream);
-                this.users = users;
-            } catch (IOException e) {
-                String msg = "Unable to load user database";
-                logger.log(Level.WARNING, msg, e);
-                throw new InvalidConfigurationException(msg);
-            }
-        }
-    }
-
-    @Override
-    public Set<Object> getAllKnownUsers() throws IllegalStateException {
-        if (users == null) {
-            throw new IllegalStateException("No user database");
-        }
-        return Collections.unmodifiableSet(users.keySet());
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModule.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.web.server.auth.BasicRole;
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-import com.redhat.thermostat.web.server.auth.UserPrincipal;
-
-/**
- * <p>
- * A login module which uses properties files for validating users and for
- * amending authenticated users with appropriate roles.
- * </p>
- * <p>
- * The properties file which will be used for user credential validation can be
- * specified via the <code>users.properties</code> option and defaults to
- * <code>$THERMOSTAT_HOME/thermostat-users.properties</code> if no such option
- * has been specified. Mappings for users to roles come from a file as specified
- * by the <code>roles.properties</code> option and defaults to
- * <code>$THERMOSTAT_HOME/thermostat-roles.properties</code> if no such option
- * has been provided.
- * </p>
- */
-public class PropertiesUsernameRolesLoginModule extends AbstractLoginModule {
-    
-    private static final Logger logger = LoggingUtils.getLogger(PropertiesUsernameRolesLoginModule.class);
-    
-    // The validator to use for authentication
-    private UserValidator validator;
-    private RolesAmender amender;
-    private String username;
-    private boolean loginOK = false;
-    
-
-    @Override
-    public void initialize(Subject subject, CallbackHandler callbackHandler,
-            Map<String, ?> sharedState, Map<String, ?> options) {
-        super.initialize(subject, callbackHandler, sharedState, options);
-        this.validator = getValidator((String) options.get("users.properties"));
-        this.amender = getRolesAmender((String) options.get("roles.properties"),
-                validator.getAllKnownUsers());
-    }
-
-    @Override
-    public boolean login() throws LoginException {
-        debugLog(Level.FINEST, "Logging in ...");
-        loginOK = false;
-        char[] password = null;
-        try {
-            Object[] creds = super.getUsernamePasswordFromCallBack();
-            username = (String)creds[0];
-            password = (char[])creds[1];
-            validator.authenticate(username, password);
-            loginOK = true;
-            debugLog(Level.FINEST, "Logged in successfully: user == '" + username + "'");
-        } catch (UserValidationException e) {
-            debugLog(Level.INFO, "Authentication failed for user '" + username + "'");
-            throw new LoginException(e.getMessage());
-        } finally {
-            clearPassword(password);
-        }
-        return loginOK;
-    }
-
-    @Override
-    public boolean commit() throws LoginException {
-        if (!loginOK) {
-            return false;
-        }
-        debugLog(Level.FINEST, "Committing principals for user '" + username + "'");
-        Set<Principal> principals = subject.getPrincipals();
-        // Tomcat uses classes as specified by the LoginModule config
-        // in order to distinguish between user principals and role principals
-        // JBoss on the other hand uses string based name matching for the
-        // user principal
-        principals.add(new UserPrincipal(username));
-        Set<BasicRole> roles;
-        try {
-            roles = amender.getRoles(username);
-        } catch (IllegalStateException e) {
-            debugLog(Level.INFO, "Failed to commit" + e.getMessage());
-            throw new LoginException();
-        }
-        principals.addAll(roles);
-        // JBoss uses the Group "Roles" as the principal
-        // for role matching
-        Group rolesRole = new RolePrincipal("Roles");
-        for (BasicRole r : roles) {
-            rolesRole.addMember(r);
-        }
-        principals.add(rolesRole);
-        return true;
-    }
-
-    @Override
-    public boolean abort() throws LoginException {
-        clearPrincipals();
-        debugLog(Level.FINEST, "Login aborted!");
-        return true;
-    }
-
-    @Override
-    public boolean logout() throws LoginException {
-        clearPrincipals();
-        debugLog(Level.FINEST, "Logged out!");
-        return true;
-    }
-    
-    private void clearPassword(char[] password) {
-        if (password == null) {
-            return;
-        }
-        for (int i= 0; i < password.length; i++) {
-            password[i] = '\0';
-        }
-    }
-
-    private void clearPrincipals() {
-        Set<Principal> principals = subject.getPrincipals();
-        principals.clear();
-    }
-
-    private UserValidator getValidator(final String usersProperties) {
-        UserValidator validator;
-        try {
-            if (usersProperties == null) {
-                debugLog(Level.FINEST, "Using default user database");
-                validator = new PropertiesUserValidator();
-            } else {
-                debugLog(Level.FINEST, "Using user database as defined in file '" + usersProperties + "'");
-                validator = new PropertiesUserValidator(usersProperties);
-            }
-        } catch (Throwable e) {
-            // Can't continue at this point, since we need this for
-            // authentication.
-            String msg = "Fatal: Failed to initialize user database";
-            logger.log(Level.SEVERE,  msg, e);
-            throw new RuntimeException(msg);
-        }
-        return validator;
-    }
-
-    private RolesAmender getRolesAmender(final String rolesProperties, final Set<Object> users) {
-        RolesAmender roleAmender;
-        try {
-            if (rolesProperties == null) {
-                debugLog(Level.FINEST, "Using default roles database");
-                roleAmender = new RolesAmender(users);
-            } else {
-                debugLog(Level.FINEST, "Using roles database as defined in file '" + rolesProperties + "'");
-                roleAmender = new RolesAmender(rolesProperties, users);
-            }
-        } catch (Throwable e) {
-            // Can't continue at this point, since we need this for
-            // authentication.
-            String msg = "Fatal: Failed to initialize role/user mapping database";
-            logger.log(Level.SEVERE, msg, e);
-            throw new RuntimeException(msg, e);
-        }
-        return roleAmender;
-    }
-
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
-import com.redhat.thermostat.web.server.ConfigurationFinder;
-import com.redhat.thermostat.web.server.auth.BasicRole;
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-
-/**
- * Class responsible for parsing roles from a properties file.
- *
- */
-class RolesAmender {
-    
-    private static final Logger logger = LoggingUtils.getLogger(RolesAmender.class);
-    private static final String DEFAULT_ROLES_FILE = "thermostat-roles.properties";
-    private static final String ROLE_SEPARATOR = ",";
-    // A username => roles mapping
-    private Map<String, Set<BasicRole>> rolesMap;
-    // The set of all users we know about
-    private final Set<Object> users; 
-
-    RolesAmender(Set<Object> users) {
-        // this is the default configuration supplied with thermostat
-        // it should not be overriden by editing this configuraton file
-        // see javadocs of PropertiesUsernameRolesLoginModule
-        this(new ConfigurationFinder(new CommonPathsImpl()).getConfiguration(DEFAULT_ROLES_FILE), users);
-    }
-    
-    RolesAmender(String rolesFile, Set<Object> users) {
-        this(new File(rolesFile), users);
-    }
-
-    RolesAmender(File rolesFile, Set<Object> users) {
-        this.users = Objects.requireNonNull(users);
-        loadRoles(rolesFile);
-    }
-    
-    /**
-     * Gets the set of roles for a specific username.
-     * 
-     * @param username the username whose roles to get
-     * @return The role-set for the given user or an empty set if this user is
-     *         not a member of any role. 
-     * @throws IllegalStateException If the roles database was null.
-     */
-    Set<BasicRole> getRoles(String username) throws IllegalStateException {
-        if (rolesMap == null) {
-            throw new IllegalStateException("Roles database missing");
-        }
-        Set<BasicRole> roles = rolesMap.get(username);
-        if (roles == null) {
-            // username not in list of roles, default to empty set for her
-            return new HashSet<>();
-        }
-        return roles;
-    }
-
-    private void loadRoles(File file) {
-        if (rolesMap == null) {
-            Properties rawRoles = new Properties();
-            try (FileInputStream stream = new FileInputStream(file)) {
-                rawRoles.load(stream);
-            } catch (IOException e) {
-                String msg = "Failed to load roles from properties";
-                logger.log(Level.SEVERE, msg, e);
-                throw new InvalidConfigurationException(msg); 
-            }
-            try {
-                prepareRolesMap(rawRoles);
-            } catch (Throwable e) {
-                String msg = "Failed to parse roles";
-                logger.log(Level.SEVERE, msg, e);
-                throw new IllegalStateException(msg);
-            }
-        }
-    }
-
-    private void prepareRolesMap(Properties rawRoles) {
-        rolesMap = new HashMap<>();
-        Map<String, RolesInfo> rolesSoFar = new HashMap<>();
-        for (Object user : users) {
-            // users came from props, this should be a safe cast to string
-            String username = (String) user;
-            String rolesRaw = rawRoles.getProperty(username);
-            if (rolesRaw == null) {
-                // Since the list of usernames is not necessarily a subset of
-                // lines listed in roles for the case where there are just users
-                // defined, but don't appear in the roles file (i.e. have no
-                // role memberships). In this case, we simply skip this entry.
-                continue;
-            }
-            rolesRaw = rolesRaw.trim();
-            String[] roles = rolesRaw.split(ROLE_SEPARATOR);
-            Set<BasicRole> uRoles = new HashSet<>();
-            for (String tmp : roles) {
-                String role = tmp.trim();
-                if (role.equals("")) {
-                    // skip empty role names
-                    continue;
-                }
-                RolesInfo info = rolesSoFar.get(role);
-                if (info == null) {
-                    // new role, define it and create role-info
-                    BasicRole r = new RolePrincipal(role);
-                    info = new RolesInfo(r);
-                    info.getMemberUsers().add(username);
-                    rolesSoFar.put(role, info);
-                }
-                info.getMemberUsers().add(username);
-                uRoles.add(info.getRole());
-            }
-            // finished one username, add it to roles map, to the intermediate
-            // set cache, and remove entry from raw roles list.
-            rolesMap.put(username, uRoles);
-            rawRoles.remove(username);
-        }
-        // what's left now are recursive role definitions.
-        Set<Object> recursiveRoles = rawRoles.keySet();
-        for (Object r: recursiveRoles) {
-            RolesInfo recRole = rolesSoFar.get((String)r);
-            if (recRole == null) {
-                // This is bad news, new role defined but no username we know
-                // of is member of that role
-                throw new IllegalStateException("Recursive role '" + r + "' defined, but no user is a member");
-            }
-            String memberRoles = rawRoles.getProperty((String)r).trim();
-            for (String tmp: memberRoles.split(ROLE_SEPARATOR)) {
-                String member = tmp.trim();
-                if (member.equals("")) {
-                    // skip empty role name
-                    continue;
-                }
-                if (users.contains(member)) {
-                    throw new IllegalStateException("User '" + member + "' part of recursive role definition!");
-                }
-                RolesInfo role = rolesSoFar.get(member);
-                if (role == null) {
-                    // new role, define it and add it as member to recursive
-                    // role
-                    BasicRole ro = new RolePrincipal(member);
-                    role = new RolesInfo(ro);
-                    rolesSoFar.put(member, role);
-                }
-                recRole.getRole().addMember(role.getRole());
-            }
-            expandRoles(recRole);
-        }
-    }
-    
-    /*
-     * Add roles to users which are member of a recursive role
-     */
-    private void expandRoles(RolesInfo recRole) {
-        for (String s : recRole.getMemberUsers()) {
-            @SuppressWarnings("unchecked") // we've added them so safe
-            Enumeration<BasicRole> members = (Enumeration<BasicRole>) recRole.getRole().members();
-            Set<BasicRole> userRoles = rolesMap.get(s);
-            while (members.hasMoreElements()) {
-                BasicRole r = members.nextElement();
-                userRoles.add(r);
-            }
-        }
-    }
-
-    /*
-     * Container data structure which is used for (role => member users) lookup.
-     */
-    static class RolesInfo {
-        
-        private final Set<String> memberUsers;
-        private final BasicRole role;
-        
-        RolesInfo(BasicRole role) {
-            this.role = role;
-            memberUsers = new HashSet<>();
-        }
-        
-        Set<String> getMemberUsers() {
-            return memberUsers;
-        }
-        
-        BasicRole getRole() {
-            return role;
-        }
-    }
-    
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidationException.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-/**
- * Exception thrown if user credential validation failed.
- *
- * @see UserValidator
- */
-public class UserValidationException extends Exception {
-
-    private static final long serialVersionUID = -4552159492521496288L;
-
-    public UserValidationException(String reason) {
-        super(reason);
-    }
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidator.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.util.Set;
-
-/**
- * Validates user's password credentials against an internal user database.
- *
- */
-public interface UserValidator {
-
-    /**
-     * Validates the given username/password combination. If no
-     * {@link UserValidationException} is thrown validation was successful.
-     * 
-     * @param username The user to validate against the internal database.
-     * @param password The password of <code>username</code>
-     * @throws UserValidationException If the user could not be validated. Reasons
-     *  as to why this exception may be thrown include:
-     *  <ul>
-     *    <li>The user does not exist in the database</li>
-     *    <li>Invalid credentials were provided</li>
-     *  </ul>
-     */
-    void authenticate(String username, char[] password) throws UserValidationException;
-
-    /**
-     * Get a read-only set of all users the system knows about. All members of
-     * the set are Strings.
-     * 
-     * @return All known users.
-     * @throws IllegalStateException If no user database is available.
-     */
-    Set<Object> getAllKnownUsers() throws IllegalStateException;
-}
-
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/AbstractContainerInfo.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import java.util.Objects;
-
-/**
- * Super class for container infos.
- *
- */
-abstract class AbstractContainerInfo {
-    
-    protected void check(String serverInfo) {
-        Objects.requireNonNull(serverInfo);
-        if (serverInfo.length() == 0) {
-            throw new IllegalArgumentException("Illegal server info: '" + serverInfo + "'");
-        }
-    }
-
-    protected abstract ContainerVersion parseVersion(String serverInfo);
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerName.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-/**
- * Enum for known-to-be-working servlet containers.
- *
- * @see ServletContainerInfo
- */
-public enum ContainerName {
-    /**
-     * Apache Tomcat.
-     * 
-     * @see http://tomcat.apache.org/
-     */
-    TOMCAT,
-    /**
-     * Eclipse Jetty
-     * 
-     * @see http://eclipse.org/jetty/
-     */
-    JETTY,
-    /**
-     * Wildfly Application Server, formerly known as JBoss AS.
-     * 
-     * @see http://www.wildfly.org/
-     * @see http://www.jboss.org/jbossas/
-     */
-    WILDFLY,
-    /**
-     * Any unknown container.
-     */
-    UNKNOWN
-}
\ No newline at end of file
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerVersion.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-/**
- * 
- * Version information of a servlet container.
- *
- */
-public class ContainerVersion {
-
-    public static final String UNKNOWN_SUFFIX = "UNKNOWN";
-    
-    private final int major;
-    private final int minor;
-    private final int micro;
-    private final String suffix;
-    
-    /**
-     * Constructor
-     * 
-     * @param major
-     *            The major version number of the servlet container.
-     * @param minor
-     *            The minor version number of the servlet container.
-     * @param micro
-     *            The micro version number of the servlet container.
-     * @param suffix
-     *            Optional suffix of the servlet container version. May be
-     *            {@code null}.
-     */
-    ContainerVersion(int major, int minor, int micro, String suffix) {
-        this.major = major;
-        this.minor = minor;
-        this.micro = micro;
-        this.suffix = suffix;
-    }
-
-    public int getMajor() {
-        return major;
-    }
-
-    public int getMinor() {
-        return minor;
-    }
-
-    public int getMicro() {
-        return micro;
-    }
-
-    /**
-     * 
-     * @return Any other version suffix, such as qualifiers. Never, {@code null}
-     *         . Returns {@link ContainerVersion#UNKNOWN_SUFFIX} if suffix was
-     *         unknown or not set.
-     * 
-     */
-    public String getSuffix() {
-        if (suffix == null) {
-            return UNKNOWN_SUFFIX;
-        }
-        return suffix;
-    }
-    
-    @Override
-    public String toString() {
-        return major + "." + minor + "." + micro + "." + getSuffix();
-    }
-    
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/JettyContainerInfo.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-
-class JettyContainerInfo extends AbstractContainerInfo implements ServletContainerInfo {
-
-    private final ContainerVersion version;
-    
-    JettyContainerInfo(String infoString) {
-        this.version = parseVersion(infoString);
-    }
-    
-    @Override
-    public ContainerName getName() {
-        return ContainerName.JETTY;
-    }
-
-    @Override
-    public ContainerVersion getContainerVersion() {
-        return version;
-    }
-    
-    @Override
-    protected ContainerVersion parseVersion(String serverInfo) {
-        super.check(serverInfo);
-        // jetty server info is of the form: jetty/x.y.z.suffix
-        String v = serverInfo.substring(serverInfo.indexOf("/") + 1);
-        String[] versions = v.split("\\.");
-        int major = Integer.parseInt(versions[0]);
-        int minor = Integer.parseInt(versions[1]);
-        int micro = Integer.parseInt(versions[2]);
-        String suffix = versions[3];
-        return new ContainerVersion(major, minor, micro, suffix);
-    }
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfo.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-/**
- * Interface providing information about the hosting servlet container.
- *
- */
-public interface ServletContainerInfo {
-    
-    /**
-     * 
-     * @return The name of the servlet container.
-     */
-    ContainerName getName();
-    
-    /**
-     * 
-     * @return The version of the servlet container.
-     */
-    ContainerVersion getContainerVersion();
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactory.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import javax.servlet.ServletContext;
-
-/**
- * Factory producing {@link ServletContainerInfo} from strings as returned from
- * {@link ServletContext#getServerInfo()}.
- *
- */
-public class ServletContainerInfoFactory {
-    
-    private static final String JETTY_PREFIX = "jetty";
-    private static final String TOMCAT_PREFIX = "Apache Tomcat";
-    private static final String WILDFLY_PREFIX = "Undertow";
-    private static final String JBOSS_AS_PREFIX = "JBoss Web";
-    
-    private final String containerInfo;
-
-    public ServletContainerInfoFactory(String containerInfo) {
-        this.containerInfo = containerInfo;
-    }
-    
-    /**
-     * 
-     * @return Information about the hosting container or {@code null} if the
-     *         servlet container is not recognized.
-     */
-    public ServletContainerInfo getInfo() {
-        if (containerInfo.startsWith(JETTY_PREFIX)) {
-            return new JettyContainerInfo(containerInfo);
-        }
-        if (containerInfo.startsWith(TOMCAT_PREFIX)) {
-            return new TomcatContainerInfo(containerInfo);
-        }
-        if (containerInfo.startsWith(WILDFLY_PREFIX)
-                || containerInfo.startsWith(JBOSS_AS_PREFIX)) {
-            return new WildflyContainerInfo(containerInfo);
-        }
-        // unknown, return null
-        return null;
-    }
-    
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfo.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-class TomcatContainerInfo extends AbstractContainerInfo implements ServletContainerInfo {
-    
-    private final ContainerVersion version;
-
-    TomcatContainerInfo(String serverInfo) {
-        this.version = parseVersion(serverInfo);
-    }
-    
-    @Override
-    public ContainerName getName() {
-        return ContainerName.TOMCAT;
-    }
-
-    @Override
-    public ContainerVersion getContainerVersion() {
-        return version;
-    }
-    
-    @Override
-    protected ContainerVersion parseVersion(String serverInfo) {
-        super.check(serverInfo);
-        // tomcat server info is of the form: Apache Tomcat/x.y.z
-        String v = serverInfo.substring(serverInfo.indexOf("/") + 1);
-        String[] versions = v.split("\\.");
-        int major = Integer.parseInt(versions[0]);
-        int minor = Integer.parseInt(versions[1]);
-        int micro = Integer.parseInt(versions[2]);
-        return new ContainerVersion(major, minor, micro, null);
-    }
-
-}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfo.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-class WildflyContainerInfo extends AbstractContainerInfo implements ServletContainerInfo {
-
-    private static final String JBOSS_WEB_PREFIX = "JBoss Web";
-    private static final String UNDERTOW_PREFIX = "Undertow";
-    private final ContainerVersion version;
-    
-    WildflyContainerInfo(String serverInfo) {
-        this.version = parseVersion(serverInfo);
-    }
-    
-    @Override
-    public ContainerName getName() {
-        return ContainerName.WILDFLY;
-    }
-
-    @Override
-    public ContainerVersion getContainerVersion() {
-        return version;
-    }
-    
-    @Override
-    protected ContainerVersion parseVersion(String serverInfo) {
-        super.check(serverInfo);
-        if (serverInfo.startsWith(JBOSS_WEB_PREFIX)) {
-            return parseJBossWeb(serverInfo);
-        } else if (serverInfo.startsWith(UNDERTOW_PREFIX)) {
-            return parseUndertow(serverInfo);
-        } else {
-            // Don't know how to parse
-            return null;
-        }
-    }
-
-    private ContainerVersion parseUndertow(String serverInfo) {
-        // Wildfly 8 uses undertow and looks like: Undertow - x.y.z.suffix
-        String version = serverInfo.substring(serverInfo.indexOf("-") + 2);
-        return parseVersionCommon(version);
-    }
-
-    private ContainerVersion parseJBossWeb(String serverInfo) {
-        // JBOSS AS 7 server info is of the form: JBoss Web/x.y.z.suffix
-        String version = serverInfo.substring(serverInfo.indexOf("/") + 1);
-        return parseVersionCommon(version);
-    }
-    
-    private ContainerVersion parseVersionCommon(String version) {
-        String[] versionTokens = version.split("\\.");
-        int major = Integer.parseInt(versionTokens[0]);
-        int minor = Integer.parseInt(versionTokens[1]);
-        int micro = Integer.parseInt(versionTokens[2]);
-        String suffix = versionTokens[3];
-        return new ContainerVersion(major, minor, micro, suffix);
-    }
-
-}
--- a/web/server/src/main/webapp/WEB-INF/web.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-<!--
-
- Copyright 2012-2017 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.
-
--->
-<!DOCTYPE web-app PUBLIC
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd" >
-
-<web-app>
-  <display-name>Archetype Created Web Application</display-name>
-
-  <servlet>
-    <servlet-name>reststorage-servlet</servlet-name>
-    <servlet-class>com.redhat.thermostat.web.server.WebStorageEndPoint</servlet-class>
-    <!-- The timeout of the token manager in ms. We use 500ms for testing. -->
-    <init-param>
-      <param-name>token-manager-timeout</param-name>
-      <param-value>500</param-value>
-    </init-param>
-  </servlet>
-
-  <servlet-mapping>
-    <servlet-name>reststorage-servlet</servlet-name>
-    <url-pattern>/storage/*</url-pattern>
-  </servlet-mapping>
-  
-  <security-constraint>
-    <web-resource-collection>
-      <web-resource-name>Entire Application</web-resource-name>
-      <url-pattern>/*</url-pattern>
-    </web-resource-collection>
-    <auth-constraint>
-      <role-name>thermostat-realm</role-name>
-    </auth-constraint>
-  </security-constraint>
-
-  <login-config>
-    <auth-method>BASIC</auth-method>
-    <realm-name>Thermostat Realm</realm-name>
-  </login-config>
-
-  <security-role>
-    <role-name>thermostat-realm</role-name>
-  </security-role>
-
-  <!-- THERMOSTAT_HOME is set via the listener below -->
-  <context-param>
-    <param-name>THERMOSTAT_HOME</param-name>
-    <param-value>/tmp/test-thermostat-home</param-value>
-  </context-param>
-
-  <listener>
-    <listener-class>com.redhat.thermostat.web.server.PropertySettingServletContextListener</listener-class>
-  </listener>
-
-</web-app>
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/CategoryManagerTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import java.util.UUID;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.web.common.SharedStateId;
-import com.redhat.thermostat.web.server.CategoryManager.CategoryIdentifier;
-
-public class CategoryManagerTest {
-
-    // CategoryIdentifier tests
-    
-    @Test
-    public void testCategoryIdentifierEquals() {
-        String catName = "foo-collection";
-        String dataClassName = "com.redhat.thermostat.storage.core.model.Foo";
-        CategoryIdentifier id = new CategoryIdentifier(catName, dataClassName);
-        assertTrue(id.equals(id));
-        assertFalse(id.equals(null));
-        String dataClass2 = "com.redhat.thermostat.storage.core.model.Bar";
-        CategoryIdentifier id2 = new CategoryIdentifier(catName, dataClass2);
-        assertFalse("different data classes", id.equals(id2));
-        String otherCatName = "bar-collection";
-        CategoryIdentifier id3 = new CategoryIdentifier(otherCatName, dataClassName);
-        assertFalse("different category names", id.equals(id3));
-        CategoryIdentifier id4 = new CategoryIdentifier(catName, dataClassName);
-        assertNotSame(id, id4);
-        assertTrue("category name and data class name match up", id.equals(id4));
-    }
-    
-    @Test
-    public void testCategoryIdentifierHashCode() {
-        String catName = "foo-collection";
-        String dataClassName = "com.redhat.thermostat.storage.core.model.Foo";
-        CategoryIdentifier id = new CategoryIdentifier(catName, dataClassName);
-        assertTrue(id.hashCode() == id.hashCode());
-        String dataClass2 = "com.redhat.thermostat.storage.core.model.Bar";
-        CategoryIdentifier id2 = new CategoryIdentifier(catName, dataClass2);
-        assertTrue("different data classes", id.hashCode() != id2.hashCode());
-        String otherCatName = "bar-collection";
-        CategoryIdentifier id3 = new CategoryIdentifier(otherCatName, dataClassName);
-        assertTrue("different category names", id.hashCode() != id3.hashCode());
-        CategoryIdentifier id4 = new CategoryIdentifier(catName, dataClassName);
-        assertNotSame(id, id4);
-        assertTrue("category name and data class name match up", id.hashCode() == id4.hashCode());
-    }
-    
-    // CategoryManager tests
-    
-    /**
-     * Verifies that only categories can be added to a manager correctly. It
-     * should add a category which has been added already (same cat-identifier)
-     * only once.
-     */
-    @Test
-    public void testPutCategory() {
-        UUID serverToken = UUID.randomUUID();
-        String catName = "foo-collection";
-        String dataClassName = "com.redhat.thermostat.storage.core.model.Foo";
-        CategoryIdentifier identifier = new CategoryIdentifier(catName, dataClassName);
-        Category<?> mockCategory = mock(Category.class);
-        CategoryManager manager = new CategoryManager();
-        SharedStateId id = manager.putCategory(serverToken, mockCategory, identifier);
-        assertNotNull(id);
-        assertEquals(serverToken, id.getServerToken());
-        assertEquals(0, id.getId());
-        CategoryIdentifier identifier2 = new CategoryIdentifier("bar", dataClassName);
-        Category<?> otherCat = mock(Category.class);
-        SharedStateId otherId = manager.putCategory(serverToken, otherCat, identifier2);
-        assertNotNull(otherId);
-        assertNotSame(id, otherId);
-        assertFalse(otherId.equals(id));
-        
-        // This should give back the same id since it's the very same identifier
-        SharedStateId thirdId = manager.putCategory(serverToken, mockCategory, identifier);
-        assertSame(id, thirdId);
-    }
-    
-    /**
-     * Verifies that NPEs get thrown when essential params are null.
-     */
-    @Test
-    public void testPutCategoryNullParams() {
-        UUID serverToken = UUID.randomUUID();
-        String catName = "foo-collection";
-        String dataClassName = "com.redhat.thermostat.storage.core.model.Foo";
-        CategoryIdentifier identifier = new CategoryIdentifier(catName, dataClassName);
-        Category<?> mockCategory = mock(Category.class);
-        CategoryManager manager = new CategoryManager();
-        try {
-            manager.putCategory(null, mockCategory, identifier);
-            fail("Expected NPE due to null server token");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        try {
-            manager.putCategory(serverToken, null, identifier);
-            fail("Expected NPE due to null category");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        try {
-            manager.putCategory(serverToken, mockCategory, null);
-            fail("Expected NPE due to null category identifier");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void testGetCategoryIdNullParams() {
-        CategoryManager manager = new CategoryManager();
-        try {
-            manager.getCategoryId(null);
-            fail("Expected NPE due to null identifier");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void canGetCategoryId() {
-        UUID serverNonce = UUID.randomUUID();
-        CategoryManager manager = new CategoryManager();
-        CategoryIdentifier catIdentifier = mock(CategoryIdentifier.class);
-        Category<?> mockCat = mock(Category.class);
-        SharedStateId id = manager.putCategory(serverNonce, mockCat, catIdentifier);
-        SharedStateId getId = manager.getCategoryId(catIdentifier);
-        assertEquals(id, getId);
-        assertSame(id, getId);
-        
-        // unknown cat identifier should return null
-        CategoryIdentifier otherIdentifier = mock(CategoryIdentifier.class);
-        assertNull(manager.getCategoryId(otherIdentifier));
-    }
-    
-    @Test
-    public void testGetCategoryNullParams() {
-        CategoryManager manager = new CategoryManager();
-        try {
-            manager.getCategory(null);
-            fail("Expected NPE due to null shared state id");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-    
-    /**
-     * Check CategoryManager.getCategory() and CategoryManager.getCategoryId()
-     * in tandem.
-     */
-    @Test
-    public void canGetCategoryCategoryId() {
-        UUID serverNonce = UUID.randomUUID();
-        CategoryManager manager = new CategoryManager();
-        assertNull(manager.getCategory(mock(SharedStateId.class)));
-        assertNull(manager.getCategoryId(mock(CategoryIdentifier.class)));
-        
-        // add an element
-        Category<?> category = mock(Category.class);
-        CategoryIdentifier catId = new CategoryIdentifier("foo", "bar");
-        SharedStateId id = manager.putCategory(serverNonce, category, catId);
-        
-        // getting it should never be null now
-        Category<?> cat = manager.getCategory(id);
-        assertNotNull(cat);
-        SharedStateId otherId = manager.getCategoryId(catId);
-        assertNotNull(otherId);
-        
-        assertSame(id, otherId);
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/ConfigurationFinderTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.shared.config.CommonPaths;
-
-public class ConfigurationFinderTest {
-
-    private File systemConfigDir = mock(File.class);
-    private File userConfigDir = mock(File.class);
-
-    private File realFile1;
-    private File realFile2;
-
-    private CommonPaths paths;
-
-    @Before
-    public void setUp() throws IOException {
-        realFile1 = Files.createTempFile("configfinder-unit-test", null).toFile();
-        realFile1.createNewFile();
-
-        realFile2 = Files.createTempFile("configfinder-unit-test", null).toFile();
-        realFile2.createNewFile();
-
-        paths = mock(CommonPaths.class);
-        when(paths.getSystemConfigurationDirectory()).thenReturn(systemConfigDir);
-        when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir);
-    }
-
-    @After
-    public void tearDown() {
-        realFile1.delete();
-        realFile2.delete();
-    }
-
-    @Test
-    public void verifyFileFromUserHomeIsUsedIfSystemHomeIsNotUsable() throws Exception {
-        ConfigurationFinder finder = new ConfigurationFinder(paths) {
-            @Override
-            File getConfigurationFile(File directory, String name) {
-                if (directory == systemConfigDir) {
-                    return new File("/does-not-exist/really-it-doesn't");
-                } else if (directory == userConfigDir) {
-                    return realFile1;
-                }
-                throw new AssertionError("Unknown test case");
-            };
-        };
-
-        File config = finder.getConfiguration("web.auth");
-        assertEquals(realFile1, config);
-    }
-
-    @Test
-    public void verifyFileFromSystemHomeIsUsedIfBothAreUsable() throws IOException {
-        final File systemFile = realFile1;
-        final File userFile = realFile2;
-
-        ConfigurationFinder finder = new ConfigurationFinder(paths) {
-            @Override
-            File getConfigurationFile(File directory, String name) {
-                if (directory == systemConfigDir) {
-                    return systemFile;
-                } else if (directory == userConfigDir) {
-                    return userFile;
-                }
-                throw new AssertionError("Unknown test case");
-            };
-        };
-
-        File config = finder.getConfiguration("web.auth");
-        assertEquals(systemFile, config);
-    }
-
-    @Test
-    public void verifyFileFromSystemHomeIsUsedIfUserHomeNotUsable() throws IOException {
-        ConfigurationFinder finder = new ConfigurationFinder(paths) {
-            @Override
-            File getConfigurationFile(File directory, String name) {
-                if (directory == systemConfigDir) {
-                    return realFile1;
-                } else if (directory == userConfigDir) {
-                    return new File("/does-not-exist/really-it-doesn't");
-                }
-                throw new AssertionError("Unknown test case");
-            };
-        };
-
-        File config = finder.getConfiguration("web.auth");
-        assertEquals(realFile1, config);
-    }
-
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/CursorManagerTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,275 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.web.server.CursorManager.CursorHolder;
-import com.redhat.thermostat.web.server.CursorManager.CursorSweeper;
-import com.redhat.thermostat.web.server.CursorManager.CursorTimer;
-
-public class CursorManagerTest {
-    
-    /**
-     * Test putting cursors which return true on hasNext()
-     * those cursors need to get tracked.
-     */
-    @Test
-    public void testPutBasicCursorHasMore() {
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class));
-        int id = manager.put(getHasMoreBatchCursor());
-        assertTrue(id >= 0);
-        assertEquals(0, id);
-        id = manager.put(getHasMoreBatchCursor());
-        assertTrue(id != 0);
-        assertEquals(1, id);
-    }
-    
-    /**
-     * Verifies that cursor IDs won't overflow.
-     */
-    @Test
-    public void testPutCursorOverflow() {
-        int startValue = Integer.MAX_VALUE - 5;
-        // construct a cursor manager with high enough counter to simulate
-        // overflow.
-        CursorManager manager = new CursorManager(startValue);
-        int numIterations = 10;
-        boolean rollOver = false;
-        for (int i = 0, id; i < numIterations; i++) {
-            id = manager.put(getHasMoreBatchCursor());
-            assertTrue(id >= 0);
-            assertFalse(id == Integer.MAX_VALUE);
-            if (id == 0) {
-                rollOver = true;
-            }
-        }
-        assertTrue("Expected id to start again from 0", rollOver);
-    }
-    
-    /**
-     * Test putting a cursor which returns false on hasNext().
-     * CursorManager should not add such cursors and should
-     * return CURSOR_NOT_STORED.
-     */
-    @Test
-    public void testPutNoHasMoreCursor() {
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class));
-        int id = manager.put(mock(Cursor.class));
-        assertEquals(CursorManager.CURSOR_NOT_STORED, id);
-    }
-    
-    private Cursor<?> getHasMoreBatchCursor() {
-        Cursor<?> c = mock(Cursor.class);
-        when(c.hasNext()).thenReturn(true);
-        return c;
-    }
-    
-    @Test
-    public void testGetInvalidId() {
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class));
-        Cursor<?> c = manager.get(CursorManager.CURSOR_NOT_STORED);
-        assertNull(c);
-    }
-    
-    /**
-     * Basic test for CursorManager.get(). Add some cursors,
-     * then add one we track the id for and verify that we
-     * can get the BatchCursor reference.
-     */
-    @Test
-    public void testGetHasMore() {
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class));
-        int num = (int)(Math.random() * 300);
-        addCursors(num, manager);
-        Cursor<?> cursor = getHasMoreBatchCursor();
-        int interestingId = manager.put(cursor);
-        num = (int)(Math.random() * 40);
-        addCursors(num, manager);
-        Cursor<?> actual = manager.get(interestingId);
-        assertSame(actual, cursor);
-    }
-    
-    @Test
-    public void testExpireCursors() {
-        Map<Integer, CursorHolder> cursors = new HashMap<>();
-        long expiredTime = System.currentTimeMillis() - ( 5 * 60 * 1000);
-        long notExpiredTime = System.currentTimeMillis();
-        cursors.put(3, new CursorHolder(mock(Cursor.class), expiredTime));
-        cursors.put(4, new CursorHolder(mock(Cursor.class), expiredTime));
-        cursors.put(5, new CursorHolder(mock(Cursor.class), notExpiredTime));
-        cursors.put(7, new CursorHolder(mock(Cursor.class), expiredTime));
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class), cursors);
-        manager.expireCursors(); // should remove old cursors
-        assertEquals(1, cursors.keySet().size());
-        assertNotNull(cursors.get(5));
-    }
-    
-    @Test
-    public void testRemoveCursor() {
-        Map<Integer, CursorHolder> cursors = new HashMap<>();
-        cursors.put(3, new CursorHolder(mock(Cursor.class), 3));
-        cursors.put(4, new CursorHolder(mock(Cursor.class), 4));
-        cursors.put(5, new CursorHolder(mock(Cursor.class), 5));
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class), cursors);
-        manager.removeCursor(3);
-        assertEquals(2, cursors.keySet().size());
-        assertNotNull(cursors.get(4));
-        assertNotNull(cursors.get(5));
-        assertNull(cursors.get(3));
-    }
-    
-    @Test
-    public void testUpdateCursorTimeStamp() {
-        Map<Integer, CursorHolder> cursors = new HashMap<>();
-        long expiredTime = System.currentTimeMillis() - ( 5 * 60 * 1000);
-        long notExpiredTime = System.currentTimeMillis();
-        cursors.put(4, new CursorHolder(mock(Cursor.class), expiredTime));
-        cursors.put(5, new CursorHolder(mock(Cursor.class), notExpiredTime));
-        cursors.put(7, new CursorHolder(mock(Cursor.class), expiredTime));
-        CursorManager manager = new CursorManager(mock(TimerRegistry.class), cursors);
-        // refresh 4's timestamp so that it's now no longer expired
-        manager.updateCursorTimeStamp(4);
-        manager.expireCursors();
-        assertEquals(2, cursors.keySet().size());
-        assertNotNull("4 has been updated and is thus still alive", cursors.get(4));
-        assertNotNull("5 was expired from the outset", cursors.get(5));
-    }
-    
-    @Test
-    public void canStartSweeperTimerViaManager() {
-        TimerRegistry registry = mock(TimerRegistry.class);
-        CursorManager manager = new CursorManager(registry);
-        manager.startSweeperTimer();
-        ArgumentCaptor<CursorTimer> timerCaptor = ArgumentCaptor.forClass(CursorTimer.class);
-        verify(registry).registerTimer(timerCaptor.capture());
-        CursorTimer timer = timerCaptor.getValue();
-        assertNotNull("expected non-null timer => timer thread started", timer);
-        assertTrue("startSweeperTimer() expected to schedule task", timer.taskScheduled);
-    }
-    
-    private void addCursors(int num, CursorManager manager) {
-        for (int i = 0; i < num; i++) {
-            manager.put(getHasMoreBatchCursor());
-        }
-    }
-    
-    // CursorTimer tests
-    
-    @Test
-    public void testCursorTimerScheduleTask() {
-        TimerTask timerTask = mock(TimerTask.class);
-        Timer timer = mock(Timer.class);
-        CursorTimer cursorTimer = new CursorTimer(timerTask, timer);
-        long threeMinutes = 3 * 60 * 1000;
-        cursorTimer.scheduleTask();
-        verify(timer).scheduleAtFixedRate(timerTask, 0, threeMinutes);
-    }
-    
-    @Test
-    public void testCursorTimerStop() {
-        TimerTask timerTask = mock(TimerTask.class);
-        Timer timer = mock(Timer.class);
-        CursorTimer cursorTimer = new CursorTimer(timerTask, timer);
-        cursorTimer.stop();
-        verify(timer).cancel();
-    }
-    
-    // CursorHolder tests
-    
-    @Test
-    public void testUpdateTimeStamp() {
-        long now = System.currentTimeMillis();
-        CursorHolder holder = new CursorHolder(mock(Cursor.class), now);
-        sleep(10);
-        holder.updateTimestamp();
-        assertTrue(now != holder.getLastUpdated());
-    }
-    
-    @Test
-    public void testCheckIsCursorExpired() {
-        long now = 0;
-        CursorHolder holder = new CursorHolder(mock(Cursor.class), now);
-        long laterTime = 10;
-        assertFalse("cursor still valid. timeout == 20ms, but only 10ms old.",
-                holder.checkIsCursorExpired(laterTime, 20));
-        assertTrue("cursor older than 5 milliseconds", holder.checkIsCursorExpired(laterTime, 5));
-    }
-    
-    @Test
-    public void testGetCursor() {
-        long now = System.currentTimeMillis();
-        Cursor<?> cursor = mock(Cursor.class);
-        CursorHolder holder = new CursorHolder(cursor, now);
-        assertSame(cursor, holder.getCursor());
-    }
-    
-    private void sleep(long millis) {
-        try {
-            Thread.sleep(millis);
-        } catch (InterruptedException e) {
-            // ignore
-        }
-    }
-    
-    // CursorSweeper tests
-    
-    public void testCursorSweeper() {
-        CursorManager manager = mock(CursorManager.class);
-        CursorSweeper sweeper = new CursorSweeper(manager);
-        sweeper.run();
-        verify(manager).expireCursors();
-    }
-
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownCategoryRegistryTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.auth.CategoryRegistration;
-
-public class KnownCategoryRegistryTest {
-    
-    private static final String DUPLICATE_CAT_NAME = "some-category";
-
-    @Test
-    public void canAddCategories() {
-        Set<String> categoryNames = new HashSet<>();
-        categoryNames.add(DUPLICATE_CAT_NAME); // duplicate
-        categoryNames.add("some-other-category");
-        Iterable<CategoryRegistration> regs = getRegs(categoryNames);
-        KnownCategoryRegistry reg = null;
-        try {
-            reg = new KnownCategoryRegistry(regs);
-        } catch (IllegalStateException e) {
-            // should not fail
-            fail(e.getMessage());
-        }
-        Set<String> actualRegs = reg.getRegisteredCategoryNames();
-        assertFalse(actualRegs.contains(null));
-        assertEquals(2, actualRegs.size());
-        for (String item: categoryNames) {
-            assertTrue(actualRegs.contains(item));
-        }
-    }
-    
-    private Iterable<CategoryRegistration> getRegs(Set<String> categoryNames) {
-        Set<CategoryRegistration> regs = new HashSet<>();
-        regs.add(new TestCategoryRegistration(categoryNames));
-        Set<String> myDup = new HashSet<>();
-        myDup.add(DUPLICATE_CAT_NAME);
-        regs.add(new TestCategoryRegistration(myDup));
-        return regs;
-    }
-
-    @Test
-    public void refuseToAddNullCategoryName() {
-        Set<String> categoryNames = new HashSet<>();
-        categoryNames.add(null);
-        categoryNames.add("some-other-category");
-        Iterable<CategoryRegistration> regs = getRegs(categoryNames);
-        try {
-            new KnownCategoryRegistry(regs);
-            fail("Should not reach here, null name added!");
-        } catch (IllegalStateException e) {
-            // pass
-        }
-    }
-    
-    /**
-     * Tests that {@code set.contains(null)} does not throw exceptions since
-     * plug-ins may supply any {@link Set} implementation. {@link TreeSet} for
-     * example throws a NPE if such a check is attempted.
-     * 
-     * See: http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2077
-     */
-    @Test
-    public void testNullCheckWithTreeSet() {
-        String categoryName = "foo-category";
-        Set<String> descs = new TreeSet<>();
-        descs.add(categoryName);
-        try {
-            descs.add(null);
-            fail("Expected NPE when adding null to TreeSet");
-        } catch (NullPointerException e) {
-            // pre-condition passes
-        }
-        Iterable<CategoryRegistration> regs = getRegs(descs);
-        KnownCategoryRegistry registry = null;
-        try {
-            registry = new KnownCategoryRegistry(regs);
-            // pass
-        } catch (NullPointerException npe) {
-            npe.printStackTrace();
-            fail("Should not have thrown NPE");
-        }
-        assertTrue("category should be known", registry.getRegisteredCategoryNames().contains(categoryName));
-    }
-    
-    @Test
-    public void canLoadRegistrationsInClasspath() {
-        KnownCategoryRegistry reg = new KnownCategoryRegistry();
-        Set<String> actualRegs = reg.getRegisteredCategoryNames();
-        assertNotNull(actualRegs);
-        // storage-core registers them. no-other modules in classpath.
-        assertEquals(6, actualRegs.size());
-    }
-    
-    private static class TestCategoryRegistration implements CategoryRegistration {
-
-        private final Set<String> catNames;
-        
-        private TestCategoryRegistration(Set<String> catNames) {
-            this.catNames = catNames;
-        }
-        
-        @Override
-        public Set<String> getCategoryNames() {
-            return catNames;
-        }
-        
-    }
-    
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
-
-public class KnownDescriptorRegistryTest {
-
-    @Test
-    public void canAddDescriptors() {
-        Set<String> descs = new HashSet<>();
-        descs.add("QUERY test WHERE 'a' = ?s");
-        descs.add("QUERY agent-config");
-        Iterable<StatementDescriptorRegistration> regs = getRegs(descs);
-        KnownDescriptorRegistry reg = new KnownDescriptorRegistry(regs);
-        Set<String> registeredDescs = null;
-        try {
-            registeredDescs = reg.getRegisteredDescriptors();
-        } catch (IllegalStateException e) {
-            fail(e.getMessage());
-        }
-        assertNotNull(registeredDescs);
-        for (String d: registeredDescs) {
-            assertTrue(descs.contains(d));
-        }
-    }
-    
-    @Test
-    public void testServiceLoadersInClassPath() {
-        KnownDescriptorRegistry reg = new KnownDescriptorRegistry();
-        Set<String> trustedDescs = reg.getRegisteredDescriptors();
-        assertNotNull(trustedDescs);
-        // storage-core registers 25 descriptors; this module has
-        // only storage-core as maven dep which registers queries.
-        // see DAOImplStatementDescriptorRegistration
-        assertEquals(25, trustedDescs.size());
-    }
-    
-    /**
-     * Tests that {@code set.contains(null)} does not throw exceptions since
-     * plug-ins may supply any {@link Set} implementation. {@link TreeSet} for
-     * example throws a NPE if such a check is attempted.
-     * 
-     * See: http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2077
-     */
-    @Test
-    public void testNullCheckWithTreeSet() {
-        String desc = "QUERY test WHERE 'a' = ?s";
-        Set<String> descs = new TreeSet<>();
-        descs.add(desc);
-        try {
-            descs.add(null);
-            fail("Expected NPE when adding null to TreeSet");
-        } catch (NullPointerException e) {
-            // pre-condition passes
-        }
-        Iterable<StatementDescriptorRegistration> regs = getRegs(descs);
-        KnownDescriptorRegistry registry = null;
-        try {
-            registry = new KnownDescriptorRegistry(regs);
-            // pass
-        } catch (NullPointerException npe) {
-            npe.printStackTrace();
-            fail("Should not have thrown NPE");
-        }
-        assertTrue("descriptor should be known", registry.getRegisteredDescriptors().contains(desc));
-    }
-    
-    @Test
-    public void cannotAddNullDescriptors() {
-        Set<String> descs = new HashSet<>();
-        descs.add("QUERY test WHERE 'a' = ?s");
-        descs.add(null);
-        Iterable<StatementDescriptorRegistration> regs = getRegs(descs);
-        try {
-            new KnownDescriptorRegistry(regs);
-            fail("Should not have accepted null descriptor");
-        } catch (IllegalStateException e) {
-            assertEquals("null statement descriptor not acceptable!", e.getMessage());
-        }
-    }
-
-    private Iterable<StatementDescriptorRegistration> getRegs(Set<String> descs) {
-        StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration(
-                descs);
-        StatementDescriptorRegistration[] regs = new StatementDescriptorRegistration[] { reg };
-        return Arrays.asList(regs);
-    }
-    
-    private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration {
-
-        private final Set<String> descs;
-        
-        private TestStatementDescriptorRegistration(Set<String> descs) {
-            this.descs = descs;
-        }
-        
-        @Override
-        public Set<String> getStatementDescriptors() {
-            return descs;
-        }
-        
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/PreparedStatementManagerTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,221 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.util.UUID;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.web.common.SharedStateId;
-
-public class PreparedStatementManagerTest {
-    
-    /**
-     * Verify that every call to put creates a new ID entry only if
-     * statements (id'ed by descriptor) are different.
-     */
-    @Test
-    public void canCreateAndPutStmt() {
-        PreparedStatementManager manager = new PreparedStatementManager();
-        UUID serverToken = UUID.randomUUID();
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class);
-        @SuppressWarnings({ "unchecked" })
-        StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused");
-        Class<TestPojo> testClass = TestPojo.class;
-        SharedStateId id = manager.createAndPutHolder(serverToken, targetStmt, testClass, testDesc);
-        assertNotNull(id);
-        assertEquals(serverToken, id.getServerToken());
-        assertEquals("counter starts with 0", 0, id.getId());
-        // do it again with a different statement
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> otherTargetStmt = mock(PreparedStatement.class);
-        @SuppressWarnings({ "unchecked" })
-        StatementDescriptor<TestPojo> otherTestDesc = new StatementDescriptor<>(mock(Category.class), "other");
-        SharedStateId otherId = manager.createAndPutHolder(serverToken, otherTargetStmt, testClass, otherTestDesc);
-        assertNotNull(otherId);
-        assertFalse(id.equals(otherId));
-        assertEquals(1, otherId.getId());
-        assertEquals(serverToken, otherId.getServerToken());
-        // do it once more with same token, which should yield the same id than
-        // we used to get for the first createAndPutHolder() call.
-        SharedStateId thirdId = manager.createAndPutHolder(serverToken, targetStmt, testClass, testDesc);
-        assertEquals(id, thirdId);
-        assertSame(id, thirdId);
-    }
-    
-    /**
-     * Verify that adding a new value when the int ID would overflow throws an
-     * exception.
-     */
-    @Test
-    public void intIdOverflowThrowsException() {
-        PreparedStatementManager manager = new PreparedStatementManager(Integer.MAX_VALUE - 1);
-        UUID serverNonce = UUID.randomUUID();
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class);
-        @SuppressWarnings({ "unchecked" })
-        StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused");
-        Class<TestPojo> testClass = TestPojo.class;
-        try {
-            manager.createAndPutHolder(serverNonce, targetStmt, testClass, testDesc);
-            fail("Should have thrown ISE due to int id overflow");
-        } catch (IllegalStateException e) {
-            assertEquals("Too many different statements!", e.getMessage());
-        }
-    }
-    
-    /**
-     * Basic parameters must not be null.
-     */
-    @Test
-    public void rejectsNullValuesAsParameters() {
-        PreparedStatementManager manager = new PreparedStatementManager();
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class);
-        @SuppressWarnings({ "unchecked" })
-        StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused");
-        Class<TestPojo> testClass = TestPojo.class;
-        try {
-            manager.createAndPutHolder(null, targetStmt, testClass, testDesc);
-            fail("Expected NPE due to null server token");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        UUID serverNonce = UUID.randomUUID();
-        try {
-            manager.createAndPutHolder(serverNonce, null, testClass, testDesc);
-            fail("Expected NPE due to null target stmt");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        try {
-            manager.createAndPutHolder(serverNonce, targetStmt, null, testDesc);
-            fail("Expected NPE due to null data class");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        try {
-            manager.createAndPutHolder(serverNonce, targetStmt, testClass, null);
-            fail("Expected NPE due to null stmt descriptor");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void canGetAddedHolderItemViaID() {
-        PreparedStatementManager manager = new PreparedStatementManager();
-        UUID serverNonce = UUID.randomUUID();
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class);
-        @SuppressWarnings({ "unchecked" })
-        StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused");
-        Class<TestPojo> testClass = TestPojo.class;
-        SharedStateId id = manager.createAndPutHolder(serverNonce, targetStmt, testClass, testDesc);
-        PreparedStatementHolder<TestPojo> holder = manager.getStatementHolder(id);
-        assertNotNull(holder);
-        assertSame(serverNonce, holder.getId().getServerToken());
-        assertSame(id, holder.getId());
-        assertSame(targetStmt, holder.getStmt());
-        assertSame(testClass, holder.getDataClass());
-        assertSame(testDesc, holder.getStatementDescriptor());
-        // do it again with an equal ID
-        SharedStateId retrievalId = new SharedStateId(0, serverNonce);
-        assertTrue(retrievalId.equals(id));
-        holder = manager.getStatementHolder(retrievalId);
-        assertEquals(id, holder.getId());
-        assertNotSame(retrievalId, holder.getId());
-        assertSame(id, holder.getId());
-        assertSame(targetStmt, holder.getStmt());
-        assertSame(testClass, holder.getDataClass());
-        assertSame(testDesc, holder.getStatementDescriptor());
-        
-        // unknown server token should return null
-        assertNull(manager.getStatementHolder(new SharedStateId(0, UUID.randomUUID())));
-    }
-    
-    @Test
-    public void canGetAddedHolderItemViaDescriptor() {
-        PreparedStatementManager manager = new PreparedStatementManager();
-        UUID serverNonce = UUID.randomUUID();
-        @SuppressWarnings("unchecked")
-        PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class);
-        @SuppressWarnings({ "unchecked" })
-        Category<TestPojo> cat = mock(Category.class);
-        StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(cat, "no-matter");
-        Class<TestPojo> testClass = TestPojo.class;
-        SharedStateId id = manager.createAndPutHolder(serverNonce, targetStmt, testClass, testDesc);
-        PreparedStatementHolder<TestPojo> holder = manager.getStatementHolder(testDesc);
-        assertNotNull(holder);
-        assertSame(serverNonce, holder.getId().getServerToken());
-        assertSame(id, holder.getId());
-        assertSame(targetStmt, holder.getStmt());
-        assertSame(testClass, holder.getDataClass());
-        assertSame(testDesc, holder.getStatementDescriptor());
-        
-        // do it again with an equal descriptor
-        StatementDescriptor<TestPojo> equalDesc = new StatementDescriptor<>(cat, "no-matter");
-        assertNotSame(testDesc, equalDesc);
-        assertEquals(testDesc, equalDesc);
-        holder = manager.getStatementHolder(equalDesc);
-        assertNotNull(holder);
-        assertSame(serverNonce, holder.getId().getServerToken());
-        assertSame(id, holder.getId());
-        assertSame(targetStmt, holder.getStmt());
-        assertSame(testClass, holder.getDataClass());
-        assertSame(testDesc, holder.getStatementDescriptor());
-    }
-
-    private static class TestPojo implements Pojo {
-        // nothing
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/PropertySettingServletContextListenerTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-
-package com.redhat.thermostat.web.server;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-
-import org.junit.After;
-import org.junit.Assume;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.Constants;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.Matchers.any;
-
-public class PropertySettingServletContextListenerTest {
-
-    @After
-    public void tearDown() {
-        System.clearProperty("THERMOSTAT_HOME");
-        System.clearProperty(Constants.IS_PROXIED_STORAGE);
-    }
-    
-    @Test
-    public void verifySetsProperty() {
-        Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null);
-        PropertySettingServletContextListener listener = new PropertySettingServletContextListener();
-        ServletContextEvent event = mock(ServletContextEvent.class);
-        ServletContext mockContext = mock(ServletContext.class);
-        when(event.getServletContext()).thenReturn(mockContext);
-        String fakeHome = "testing";
-        when(mockContext.getInitParameter(any(String.class))).thenReturn(fakeHome);
-        listener.contextInitialized(event);
-        assertEquals(fakeHome, System.getProperty("THERMOSTAT_HOME"));
-        boolean isProxyStorage = Boolean.getBoolean(Constants.IS_PROXIED_STORAGE);
-        assertTrue("Expected to set proxied storage property", isProxyStorage);
-    }
-    
-    @Test
-    public void verifyClearsProperty() {
-        System.setProperty("THERMOSTAT_HOME", "somevalue");
-        PropertySettingServletContextListener listener = new PropertySettingServletContextListener();
-        listener.contextDestroyed(null);
-        assertNull(System.getProperty("THERMOSTAT_HOME"));
-        boolean isProxyStorage = Boolean.getBoolean(Constants.IS_PROXIED_STORAGE);
-        assertFalse("Expected context listener to clear proxied storage property", isProxyStorage);
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/TimerRegistryTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import java.util.List;
-
-import org.junit.Test;
-
-public class TimerRegistryTest {
-
-    @Test
-    public void canRegisterTimers() {
-        @SuppressWarnings("unchecked")
-        List<StoppableTimer> timers = mock(List.class);
-        TimerRegistry reg = new TimerRegistry(timers);
-        StoppableTimer mockTimer = mock(StoppableTimer.class);
-        reg.registerTimer(mockTimer);
-        verify(timers).add(mockTimer);
-        verifyNoMoreInteractions(timers);
-    }
-    
-    @Test
-    public void shutdownStopsTimers() {
-        TimerRegistry registry = new TimerRegistry();
-        StoppableTimer mockTimer = mock(StoppableTimer.class);
-        StoppableTimer timer2 = mock(StoppableTimer.class);
-        registry.registerTimer(timer2);
-        registry.registerTimer(mockTimer);
-        registry.shutDown();
-        verify(timer2).stop();
-        verify(mockTimer).stop();
-        verifyNoMoreInteractions(mockTimer);
-        verifyNoMoreInteractions(timer2);
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/TokenManagerTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Matchers.isA;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.web.server.TokenManager.TokenManagerTimer;
-
-public class TokenManagerTest {
-
-    /**
-     * Since we want to make sure that the action-name parameter for
-     * CMD channel interactions are trustworthy, we SHA256 hash the client
-     * token + the action name parameter, convert the resulting bytes into
-     * a hex string and finally put it into the tokens map. This way
-     * verification of the token should never pass if either the client token
-     * or the action-name was wrong.
-     * 
-     * This test verifies that we have SHA256 hex-strings as keys. SHA256 hex
-     * strings are generated using the the client token first and then the
-     * action name for the digest.
-     */
-    @Test
-    public void generateTokenTest() {
-        TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class));
-        String clientToken = "something";
-        String action = "myAction";
-        byte[] token = tokenManager.generateToken(clientToken.getBytes(), action);
-        String expectedKey = "8d51bc31b39f54a1a12f2f94f09371ad5afe2263c1fdb7a3785aaacea6a386ef";
-        byte[] actualToken = tokenManager.getStoredToken(expectedKey);
-        assertNotNull(actualToken);
-        assertTrue(Arrays.equals(token, actualToken));
-    }
-    
-    @Test
-    public void canConvertBytesToHexString() throws UnsupportedEncodingException {
-        byte[] expected = new byte[] {
-                (byte)0xff, 0x6f, 0x6d, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x65, 0x48, 0x61, 0x73, 0x68 
-        };
-        TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class));
-        String actual = tokenManager.convertBytesToHexString(expected);
-        assertEquals(expected.length * 2, actual.length());
-        assertEquals("ff6f6d65537472696e67576548617368", actual);
-    }
-    
-    @Test
-    public void generateTokenCanNotBeReusedTest() {
-        TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class));
-        String clientToken = "something";
-        String action = "myAction";
-        byte[] token = tokenManager.generateToken(clientToken.getBytes(), action);
-        assertTrue(tokenManager.verifyToken(clientToken.getBytes(), token, action));
-        // try again with same action name, which should not verify
-        assertFalse(tokenManager.verifyToken(clientToken.getBytes(), token, action));
-    }
-
-    @Test
-    public void generateAndVerifyTokenTest() {
-        TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class));
-        String clientToken = "something";
-        String action = "myAction";
-        byte[] token = tokenManager.generateToken(clientToken.getBytes(), action);
-        assertTrue(tokenManager.verifyToken(clientToken.getBytes(), token, action));
-        // try again with different action name, which should not verify
-        String wrongAction = "someAction";
-        assertFalse(tokenManager.verifyToken(clientToken.getBytes(), token, wrongAction));
-    }
-    
-    @Test
-    public void instantiationRegistersTimer() {
-        TimerRegistry registry = mock(TimerRegistry.class);
-        new TokenManager(registry);
-        verify(registry).registerTimer(isA(TokenManagerTimer.class));
-        registry = mock(TimerRegistry.class);
-        TokenManagerTimer timer = mock(TokenManagerTimer.class);
-        new TokenManager(registry, timer);
-        verify(registry).registerTimer(timer);
-    }
-    
-    // TokenManagerTimer tests
-    
-    @Test
-    public void tokenManagerTimerCanScheduleTasks() {
-        Timer mockTimer = mock(Timer.class);
-        TokenManagerTimer timer = new TokenManagerTimer(mockTimer);
-        TimerTask task = mock(TimerTask.class);
-        int timeout = -100;
-        timer.schedule(task, timeout);
-        verify(mockTimer).schedule(task, -100);
-    }
-    
-    @Test
-    public void tokenManagerTimerCanStopTimer() {
-        Timer mockTimer = mock(Timer.class);
-        TokenManagerTimer timer = new TokenManagerTimer(mockTimer);
-        timer.stop();
-        verify(mockTimer).cancel();
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndPointUnitTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,367 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Matchers.eq;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.attribute.FileAttribute;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import com.redhat.thermostat.common.internal.test.Bug;
-import com.redhat.thermostat.shared.config.OS;
-import com.redhat.thermostat.storage.core.Storage;
-import org.junit.After;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-import com.redhat.thermostat.web.server.auth.WebStoragePathHandler;
-
-/**
- * A test class for {@link WebStorageEndPoint}. It should contain tests for
- * which we don't need the servlet deployed in a container. I.e. which are
- * more of the unit-test nature (rather than of the functional test nature).
- *
- */
-public class WebStorageEndPointUnitTest {
-
-    private static final String TH_HOME_PROP_NAME = "THERMOSTAT_HOME";
-
-    private StorageFactoryProvider storageFactoryProvider;
-    private StorageFactory storageFactory;
-    private Storage storage;
-
-    @Before
-    public void setup() {
-        storage = mock(Storage.class);
-        storageFactory = mock(StorageFactory.class);
-        storageFactoryProvider = mock(StorageFactoryProvider.class);
-
-        when(storageFactoryProvider.createStorageFactory()).thenReturn(storageFactory);
-        when(storageFactory.getStorage(anyString(), anyString(), any(CommonPaths.class), any(StorageCredentials.class)))
-                .thenReturn(storage);
-    }
-
-    @After
-    public void tearDown() {
-        System.clearProperty(TH_HOME_PROP_NAME);
-    }
-    
-    /**
-     * Makes sure that all paths we dispatch to, dispatch to
-     * {@link WebStoragePathHandler} annotated methods.
-     * 
-     * @throws Exception
-     */
-    @Test
-    public void ensureAuthorizationCovered() throws Exception {
-        // manually maintained list of path handlers which should include
-        // authorization checks
-        final String[] authPaths = new String[] {
-                "prepare-statement", "query-execute", "write-execute", "register-category",
-                "save-file", "load-file", "purge", "ping", "generate-token", "verify-token",
-                "get-more"
-        };
-        Map<String, Boolean> checkedAutPaths = new HashMap<>();
-        for (String path: authPaths) {
-            checkedAutPaths.put(path, false);
-        }
-        int methodsReqAuthorization = 0;
-        for (Method method: WebStorageEndPoint.class.getDeclaredMethods()) {
-            if (method.isAnnotationPresent(WebStoragePathHandler.class)) {
-                methodsReqAuthorization++;
-                WebStoragePathHandler annot = method.getAnnotation(WebStoragePathHandler.class);
-                try {
-                    // this may NPE if there is something funny going on in
-                    // WebStorageEndPoint (e.g. one method annotated but this
-                    // reference list has not been updated).
-                    if (!checkedAutPaths.get(annot.path())) {
-                        // mark path as covered
-                        checkedAutPaths.put(annot.path(), true);
-                    } else {
-                        throw new AssertionError(
-                                "method "
-                                        + method
-                                        + " annotated as web storage path handler (path '"
-                                        + annot.path()
-                                        + "'), but not in reference list we know about!");
-                    }
-                } catch (NullPointerException e) {
-                    throw new AssertionError("Don't know about path '"
-                            + annot.path() + "'");
-                }
-            }
-        }
-        // at this point we should have all dispatched paths covered
-        for (String path: authPaths) {
-            assertTrue(
-                    "Is " + path
-                          + " marked with @WebStoragePathHandler and have proper authorization checks been included?",
-                    checkedAutPaths.get(path));
-        }
-        assertEquals(authPaths.length, methodsReqAuthorization);
-    }
-    
-    @Test
-    public void initThrowsRuntimeExceptionIfThermostatHomeNotSet() {
-        Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null);
-        WebStorageEndPoint endpoint = new WebStorageEndPoint();
-        ServletConfig config = mock(ServletConfig.class);
-        try {
-            endpoint.init(config);
-            fail("Thermostat home was not set in config, should not get here!");
-        } catch (RuntimeException e) {
-            // pass
-            assertTrue(e.getMessage().contains(TH_HOME_PROP_NAME));
-        } catch (ServletException e) {
-            fail(e.getMessage());
-        }
-        // set config with non-existing dir
-        when(config.getInitParameter(TH_HOME_PROP_NAME)).thenReturn("not-existing");
-        try {
-            endpoint.init(config);
-            fail("Thermostat home was set in config but file does not exist, should have died!");
-        } catch (RuntimeException e) {
-            // pass
-            assertTrue(e.getMessage().contains(TH_HOME_PROP_NAME));
-        } catch (ServletException e) {
-            fail(e.getMessage());
-        }
-    }
-    
-    @Test
-    public void initThrowsRuntimeExceptionIfSSLPropertiesNotReadable() throws Exception {
-        Assume.assumeTrue(!OS.IS_WINDOWS); // Windows can't set directories non-readable
-        ThCreatorResult result = null;
-        try {
-            result = creatWorkingThermostatHome();
-            // explicitly remove read perms from etc directory
-            result.etcDir.setExecutable(false);
-            assertFalse(result.sslProperties.canRead());
-
-            WebStorageEndPoint endpoint = new WebStorageEndPoint();
-            System.setProperty(TH_HOME_PROP_NAME, result.thermostatHome.toFile().getAbsolutePath());
-            try {
-                endpoint.init(mock(ServletConfig.class));
-                fail("should have failed to initialize! can't read ssl.properties");
-            } catch (RuntimeException e) {
-                assertTrue(e.getMessage().contains("ssl.properties"));
-            }
-        } finally {
-            result.etcDir.setExecutable(true);
-            if (result.thermostatHome != null) {
-                WebstorageEndpointTestUtils.deleteDirectoryRecursive(result.thermostatHome);
-            }
-        }
-    }
-    
-    @Test
-    public void initThrowsRuntimeExceptionIfSSLPropertiesDoesnotExist() throws Exception {
-        Path testThermostatHome = null;
-        try {
-            testThermostatHome = Files.createTempDirectory(
-                    "bar-thermostat-home-", new FileAttribute[] {});
-            File thFile = testThermostatHome.toFile();
-            WebStorageEndPoint endpoint = new WebStorageEndPoint();
-            System.setProperty(TH_HOME_PROP_NAME, thFile.getAbsolutePath());
-            try {
-                endpoint.init(mock(ServletConfig.class));
-                fail("should have failed to initialize, ssl.properties not existing!");
-            } catch (RuntimeException e) {
-                assertTrue(e.getMessage().contains("ssl.properties"));
-            }
-        } finally {
-            if (testThermostatHome != null) {
-                WebstorageEndpointTestUtils.deleteDirectoryRecursive(testThermostatHome);
-            }
-        }
-    }
-    
-    /**
-     * Verifies that Servlet.init() sets servlet context attributes correctly.
-     * @throws ServletException 
-     * @throws IOException 
-     */
-    @Test
-    public void testSetServletAttribute() throws ServletException, IOException {
-        final ServletContext mockContext = mock(ServletContext.class);
-        when(mockContext.getServerInfo()).thenReturn("jetty/9.1.0.v20131115");
-        ConfigurationFinder finder = mock(ConfigurationFinder.class);
-        when(finder.getConfiguration(anyString())).thenReturn(mock(File.class));
-        @SuppressWarnings("serial")
-        WebStorageEndPoint endpoint = new WebStorageEndPoint(null, null, finder, storageFactoryProvider) {
-            @Override
-            public ServletContext getServletContext() {
-                return mockContext;
-            }
-        };
-        ServletConfig config = mock(ServletConfig.class);
-        when(config.getInitParameter(WebStorageEndPoint.STORAGE_CLASS)).thenReturn("fooKlazz"); // let it fail through
-        when(config.getInitParameter(WebStorageEndPoint.STORAGE_ENDPOINT)).thenReturn("fooEndPoint");
-        ThCreatorResult result = creatWorkingThermostatHome();
-        System.setProperty(TH_HOME_PROP_NAME, result.thermostatHome.toFile().getAbsolutePath());
-        endpoint.init(config);
-        ArgumentCaptor<CategoryManager> categoryManagerCaptor = ArgumentCaptor.forClass(CategoryManager.class);
-        ArgumentCaptor<PreparedStatementManager> prepStmtManagerCaptor = ArgumentCaptor.forClass(PreparedStatementManager.class);
-        ArgumentCaptor<TokenManager> tokenManagerCaptor = ArgumentCaptor.forClass(TokenManager.class);
-        ArgumentCaptor<UUID> serverTokenCaptor = ArgumentCaptor.forClass(UUID.class);
-        verify(mockContext).setAttribute(eq("category-manager"), categoryManagerCaptor.capture());
-        verify(mockContext).setAttribute(eq("prepared-stmt-manager"), prepStmtManagerCaptor.capture());
-        verify(mockContext).setAttribute(eq("token-manager"), tokenManagerCaptor.capture());
-        verify(mockContext).setAttribute(eq("server-token"), serverTokenCaptor.capture());
-        assertNotNull(categoryManagerCaptor.getValue());
-        assertNotNull(prepStmtManagerCaptor.getValue());
-        assertNotNull(tokenManagerCaptor.getValue());
-        assertNotNull(serverTokenCaptor.getValue());
-    }
-    
-    @Test
-    public void testShutDownCancelsTimers() {
-        TimerRegistry registry = mock(TimerRegistry.class);
-        WebStorageEndPoint endpoint = new WebStorageEndPoint(registry, null, null, storageFactoryProvider);
-        endpoint.destroy();
-        verify(registry).shutDown();
-    }
-    
-    /**
-     * If storage credentials are not found then null is expected to get returned.
-     */
-    @Test
-    public void storageCredentialsNull() throws IOException {
-        CommonPaths paths = mock(CommonPaths.class);
-        TimerRegistry registry = mock(TimerRegistry.class);
-        ConfigurationFinder finder = mock(ConfigurationFinder.class);
-        when(finder.getConfiguration("web.auth")).thenReturn(null);
-
-        WebStorageEndPoint endpoint = new WebStorageEndPoint(registry, paths, finder, storageFactoryProvider);
-        StorageCredentials creds = endpoint.getStorageCredentials();
-
-        assertNull(creds);
-    }
-
-    @Test
-    @Bug(id = "PR2941",
-            url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2941",
-            summary = "Concurrent webstorage connections may cause storage exceptions")
-    public void testStorageIsCreatedOnceOnInit() throws Exception {
-        final ServletContext mockContext = mock(ServletContext.class);
-        when(mockContext.getServerInfo()).thenReturn("jetty/9.1.0.v20131115");
-        ConfigurationFinder finder = mock(ConfigurationFinder.class);
-        when(finder.getConfiguration(anyString())).thenReturn(mock(File.class));
-        @SuppressWarnings("serial")
-        WebStorageEndPoint endpoint = new WebStorageEndPoint(null, null, finder, storageFactoryProvider) {
-            @Override
-            public ServletContext getServletContext() {
-                return mockContext;
-            }
-        };
-        ServletConfig config = mock(ServletConfig.class);
-        when(config.getInitParameter(WebStorageEndPoint.STORAGE_CLASS)).thenReturn("fooKlazz"); // let it fail through
-        when(config.getInitParameter(WebStorageEndPoint.STORAGE_ENDPOINT)).thenReturn("fooEndPoint");
-        ThCreatorResult result = creatWorkingThermostatHome();
-        System.setProperty(TH_HOME_PROP_NAME, result.thermostatHome.toFile().getAbsolutePath());
-
-        // not created yet
-        verifyZeroInteractions(storageFactoryProvider);
-        verifyZeroInteractions(storageFactory);
-
-        endpoint.init(mock(ServletConfig.class));
-
-        // created once
-        verify(storageFactoryProvider).createStorageFactory();
-        verify(storageFactory).getStorage(anyString(), anyString(), any(CommonPaths.class), any(StorageCredentials.class));
-
-        endpoint.init(mock(ServletConfig.class));
-
-        // still only once
-        verify(storageFactoryProvider).createStorageFactory();
-        verify(storageFactory).getStorage(anyString(), anyString(), any(CommonPaths.class), any(StorageCredentials.class));
-    }
-
-    private ThCreatorResult creatWorkingThermostatHome() throws IOException {
-        Path testThermostatHome = Files.createTempDirectory(
-                "foo-thermostat-home-", new FileAttribute[] {});
-        File thFile = testThermostatHome.toFile();
-        File etcDir = new File(thFile, "etc");
-        etcDir.mkdir();
-        assertTrue(etcDir.exists());
-        assertTrue(etcDir.canWrite());
-        File sslProperties = new File(etcDir, "ssl.properties");
-        sslProperties.createNewFile();
-        assertTrue(sslProperties.canRead());
-        return new ThCreatorResult(testThermostatHome, etcDir, sslProperties);
-    }
-    
-    private static class ThCreatorResult {
-        private final Path thermostatHome;
-        private final File etcDir;
-        private final File sslProperties;
-        
-        ThCreatorResult(Path thermostatHome, File etcFile, File sslProperties) {
-            this.thermostatHome = thermostatHome;
-            this.etcDir = etcFile;
-            this.sslProperties = sslProperties;
-        }
-    }
-    
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1836 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Type;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.ProtocolException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.nio.file.Path;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
-import javax.security.auth.login.Configuration;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.codec.binary.Base64;
-import org.eclipse.jetty.jaas.JAASLoginService;
-import org.eclipse.jetty.security.DefaultUserIdentity;
-import org.eclipse.jetty.security.LoginService;
-import org.eclipse.jetty.security.MappedLoginService;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.UserIdentity;
-import org.eclipse.jetty.util.component.LifeCycle;
-import org.eclipse.jetty.util.component.LifeCycle.Listener;
-import org.eclipse.jetty.util.security.Password;
-import org.eclipse.jetty.webapp.WebAppContext;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.reflect.TypeToken;
-import com.redhat.thermostat.common.internal.test.FreePortFinder;
-import com.redhat.thermostat.common.internal.test.FreePortFinder.TryPort;
-import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.AggregateQuery;
-import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction;
-import com.redhat.thermostat.storage.core.BackingStorage;
-import com.redhat.thermostat.storage.core.Categories;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.CategoryAdapter;
-import com.redhat.thermostat.storage.core.CloseOnSave;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.Entity;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.ParsedStatement;
-import com.redhat.thermostat.storage.core.Persist;
-import com.redhat.thermostat.storage.core.PreparedParameter;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.auth.CategoryRegistration;
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.model.BasePojo;
-import com.redhat.thermostat.storage.model.HostInfo;
-import com.redhat.thermostat.storage.query.BinarySetMembershipExpression;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.common.PreparedStatementResponseCode;
-import com.redhat.thermostat.web.common.SharedStateId;
-import com.redhat.thermostat.web.common.WebPreparedStatement;
-import com.redhat.thermostat.web.common.WebPreparedStatementResponse;
-import com.redhat.thermostat.web.common.WebQueryResponse;
-import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory;
-import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory;
-import com.redhat.thermostat.web.server.auth.BasicRole;
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-import com.redhat.thermostat.web.server.auth.Roles;
-import com.redhat.thermostat.web.server.auth.UserPrincipal;
-
-public class WebStorageEndpointTest {
-
-    @Entity
-    public static class TestClass extends BasePojo {
-        
-        public TestClass() {
-            super(null);
-        }
-        
-        private String key1;
-        private int key2;
-        @Persist
-        public String getKey1() {
-            return key1;
-        }
-        @Persist
-        public void setKey1(String key1) {
-            this.key1 = key1;
-        }
-        @Persist
-        public int getKey2() {
-            return key2;
-        }
-        @Persist
-        public void setKey2(int key2) {
-            this.key2 = key2;
-        }
-        public boolean equals(Object o) {
-            if (! (o instanceof TestClass)) {
-                return false;
-            }
-            TestClass other = (TestClass) o;
-            return key1.equals(other.key1) && key2 == other.key2;
-        }
-    }
-
-    private Server server;
-    private int port;
-    private BackingStorage mockStorage;
-
-    private static Key<String> key1;
-    private static Key<Integer> key2;
-    private static Category<TestClass> category;
-    private static String categoryName = "test";
-    private static File testThermostatHome;
-
-    @BeforeClass
-    public static void setupCategory() {
-        key1 = new Key<>("key1");
-        key2 = new Key<>("key2");
-        category = new Category<>(categoryName, TestClass.class, key1, key2);
-    }
-
-    @AfterClass
-    public static void cleanupCategory() {
-        Categories.remove(category);
-        category = null;
-        key2 = null;
-        key1 = null;
-        
-        if (testThermostatHome != null) {
-            Path testTh = testThermostatHome.toPath();
-            try {
-                WebstorageEndpointTestUtils.deleteDirectoryRecursive(testTh);
-            } catch (IOException e) {
-                e.printStackTrace(System.err);
-            }
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        
-        mockStorage = mock(BackingStorage.class);
-        StorageFactoryImpl.setStorage(mockStorage);
-    }
-
-    private void startServer(int port, LoginService loginService) throws Exception {
-        server = new Server(port);
-        // This makes the test use the web.xml in src/main/webapp. That's
-        // also where the test's thermostat home is set up via 
-        // the context listener. THERMOSTAT_HOME == /tmp/test-thermostat-home
-        // See src/main/webapp/WEB-INF/web.xml
-        final WebAppContext ctx = new WebAppContext("src/main/webapp", "/");
-        ctx.getSecurityHandler().setLoginService(loginService);
-        // We get access to the THERMOSTAT_HOME value once the context has
-        // been started.
-        ctx.addLifeCycleListener(new Listener() {
-
-            @Override
-            public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) {
-                // nothing
-            }
-
-            @Override
-            public void lifeCycleStarted(LifeCycle arg0) {
-                // In Servlet.init() we check if ssl.properties exists. We need
-                // to create that file in order for the tests to get past this
-                // check.
-                File thermostatHome = new File(ctx.getInitParameter("THERMOSTAT_HOME"));
-                if (testThermostatHome == null) {
-                    testThermostatHome = thermostatHome;
-                }
-                if (!thermostatHome.exists()) {
-                    thermostatHome.mkdir();
-                }
-                File configDirectory = new File(thermostatHome, "etc");
-                if (!configDirectory.exists()) {
-                    configDirectory.mkdir();
-                }
-                File sslProperties = new File(configDirectory, "ssl.properties");
-                // only creates file if it doesn't exist yet
-                try {
-                    sslProperties.createNewFile();
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-                File webAuthFile = new File(configDirectory, "web.auth");
-                // only creates file if it doesn't exist yet
-                try {
-                    webAuthFile.createNewFile();
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-
-            @Override
-            public void lifeCycleStarting(LifeCycle arg0) {
-                // nothing
-            }
-
-            @Override
-            public void lifeCycleStopped(LifeCycle arg0) {
-                // nothing
-            }
-
-            @Override
-            public void lifeCycleStopping(LifeCycle arg0) {
-                // nothing
-            }
-            
-        });
-        server.setHandler(ctx);
-        server.start();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        
-        // some tests don't use server
-        if (server != null) {
-            server.stop();
-            server.join();
-        }
-        KnownCategoryRegistryFactory.setInstance(null);
-        KnownDescriptorRegistryFactory.setKnownDescriptorRegistry(null);
-    }
-
-    @Test
-    public void authorizedPrepareQueryWithUnTrustedDescriptor() throws Exception {
-        String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42";
-        // setup a statement descriptor set so as to mimic a not trusted desc
-        String wrongDescriptor = "QUERY something-other WHERE 'a' = true";
-        setupTrustedStatementRegistry(wrongDescriptor);
-        
-        String[] roleNames = new String[] {
-                Roles.REGISTER_CATEGORY,
-                Roles.PREPARE_STATEMENT,
-                Roles.ACCESS_REALM,
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        // This makes register category work for the "test" category.
-        // Undone via @After
-        setupTrustedCategory(categoryName);
-        SharedStateId catId = registerCategoryAndGetId(category, testuser, password);
-        
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/prepare-statement");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        conn.setDoInput(true);
-        conn.setDoOutput(true);
-        Gson gson = new GsonBuilder()
-                        .registerTypeAdapterFactory(new PojoTypeAdapterFactory())
-                        .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory())
-                        .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory())
-                        .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory())
-                        .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory())
-                        .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory())
-                        .create();
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId);
-        out.write(body + "\n");
-        out.flush();
-
-        Reader in = new InputStreamReader(conn.getInputStream());
-        WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class);
-        assertEquals("descriptor not trusted, so expected number should be negative!", -1, response.getNumFreeVariables());
-        assertEquals(WebPreparedStatementResponse.ILLEGAL_STATEMENT, response.getStatementId().getId());
-        assertEquals("application/json; charset=UTF-8", conn.getContentType());
-    }
-
-    /**
-     * Tests a successful query execution, starting from preparing the query,
-     * then executing the query and finally getting more results for the query.
-     * 
-     * @throws Exception
-     * 
-     * @see {@link #authorizedPrepareQueryWithTrustedDescriptorGetMoreFail()}
-     */
-    @SuppressWarnings({ "rawtypes" })
-    @Test
-    public void authorizedPrepareQueryWithTrustedDescriptorSuccessfulGetMore() throws Exception {
-        // Get the trusted descriptor
-        String strDescriptor = setupPreparedQueryWithTrustedDescriptor();
-        SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2");
-        
-        // Prepare the query
-        boolean moreBatches = true;
-        TrustedPreparedQueryTestResult prepareQueryResult = prepareQuery(catId, strDescriptor, moreBatches);
-        
-        Type typeToken = new TypeToken<WebQueryResponse<TestClass>>(){}.getType();
-
-        WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(1, prepareQueryResult.stmtId);
-        stmt.setString(0, "fluff");
-        
-        // Execute the query, preserver the cookie
-        String cookieValue = executeQuery(prepareQueryResult.gson, prepareQueryResult.mockMongoQuery, typeToken, stmt, moreBatches);
-        
-        // Simulate getting more elements
-        int cursorId = 0;
-        int batchSize = 3;
-        // stub the underlying cursor so that it can fill up a single batch (3)
-        // and leaves one element more => 3 + 1.
-        when(prepareQueryResult.cursor.hasNext()).thenReturn(true)  // 1
-                              .thenReturn(true)  // 2
-                              .thenReturn(true)  // 3
-                              .thenReturn(true)  // 4
-                              .thenReturn(false);
-                              
-                              
-        when(prepareQueryResult.cursor.next())
-                    .thenReturn(new TestClass()) // 1
-                    .thenReturn(new TestClass()) // 2
-                    .thenReturn(new TestClass()) // 3
-                    .thenReturn(new TestClass()) // 4
-                    .thenReturn(null);
-        when(prepareQueryResult.cursor.getBatchSize()).thenReturn(batchSize);
-        URL url = new URL(getEndpoint() + "/get-more");
-        HttpURLConnection getMoreConn = (HttpURLConnection) url.openConnection();
-        getMoreConn.setRequestMethod("POST");
-        setCookie(getMoreConn, cookieValue);
-        sendAuthentication(getMoreConn, "ignored1", "ignored2");
-        getMoreConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        getMoreConn.setDoInput(true);
-        getMoreConn.setDoOutput(true);
-        
-        OutputStreamWriter out = new OutputStreamWriter(getMoreConn.getOutputStream());
-        String body = "prepared-stmt-id=" + URLEncoder.encode(prepareQueryResult.gson.toJson(stmt.getStatementId()), "UTF-8") + "&";
-        body += "cursor-id=" + cursorId + "&";
-        body += "batch-size=" + batchSize;
-        out.write(body);
-        out.flush();
-        
-        InputStreamReader in = new InputStreamReader(getMoreConn.getInputStream());
-        WebQueryResponse result = prepareQueryResult.gson.fromJson(in, typeToken);
-        assertEquals(3, result.getResultList().length);
-        assertEquals(cursorId, result.getCursorId());
-        assertTrue("There was one more result than the batch size", result.hasMoreBatches());
-        assertEquals("application/json; charset=UTF-8", getMoreConn.getContentType());
-        // expected setBatchSize to be called via get-more request
-        verify(prepareQueryResult.cursor).setBatchSize(batchSize);
-    }
-    
-    /**
-     * Tests authorized prepared query which attempts to do a get-more but does
-     * not have a cursor in the user's cursor manager.
-     * 
-     * @throws Exception
-     * 
-     * @see {@link #authorizedPrepareQueryWithTrustedDescriptorSuccessfulGetMore}
-     */
-    @SuppressWarnings({ "rawtypes" })
-    @Test
-    public void authorizedPrepareQueryWithTrustedDescriptorGetMoreFail() throws Exception {
-        // Get the trusted descriptor
-        String strDescriptor = setupPreparedQueryWithTrustedDescriptor();
-        SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2");
-        
-        // Prepare the query
-        boolean moreBatches = false;
-        TrustedPreparedQueryTestResult prepareQueryResult = prepareQuery(catId, strDescriptor, moreBatches);
-        
-        Type typeToken = new TypeToken<WebQueryResponse<TestClass>>(){}.getType();
-
-        WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(1, prepareQueryResult.stmtId);
-        stmt.setString(0, "fluff");
-        
-        // Execute the query, preserver the cookie
-        String cookieValue = executeQuery(prepareQueryResult.gson, prepareQueryResult.mockMongoQuery, typeToken, stmt, moreBatches);
-        
-        // Simulate getting more elements
-        int cursorId = 0;
-        int batchSize = 3;
-        // stub the underlying cursor so that it can fill up a single batch (3)
-        // and leaves one element more => 3 + 1.
-        when(prepareQueryResult.cursor.hasNext()).thenReturn(true)  // 1
-                              .thenReturn(true)  // 2
-                              .thenReturn(true)  // 3
-                              .thenReturn(false)  // 4
-                              .thenReturn(false);
-                              
-                              
-        when(prepareQueryResult.cursor.next())
-                    .thenReturn(new TestClass()) // 1
-                    .thenReturn(new TestClass()) // 2
-                    .thenReturn(new TestClass()) // 3
-                    .thenReturn(null)            // 4
-                    .thenReturn(null);
-        when(prepareQueryResult.cursor.getBatchSize()).thenReturn(batchSize);
-        URL url = new URL(getEndpoint() + "/get-more");
-        HttpURLConnection getMoreConn = (HttpURLConnection) url.openConnection();
-        getMoreConn.setRequestMethod("POST");
-        setCookie(getMoreConn, cookieValue);
-        sendAuthentication(getMoreConn, "ignored1", "ignored2");
-        getMoreConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        getMoreConn.setDoInput(true);
-        getMoreConn.setDoOutput(true);
-        
-        OutputStreamWriter out = new OutputStreamWriter(getMoreConn.getOutputStream());
-        String body = "prepared-stmt-id=" + URLEncoder.encode(prepareQueryResult.gson.toJson(stmt.getStatementId()), "UTF-8") + "&";
-        body += "cursor-id=" + cursorId + "&";
-        body += "batch-size=" + batchSize;
-        out.write(body);
-        out.flush();
-        
-        InputStreamReader in = new InputStreamReader(getMoreConn.getInputStream());
-        WebQueryResponse result = prepareQueryResult.gson.fromJson(in, typeToken);
-        assertEquals(PreparedStatementResponseCode.GET_MORE_NULL_CURSOR, result.getResponseCode());
-        assertNotNull(result.getResultList());
-        assertEquals(0, result.getResultList().length);
-        assertEquals(cursorId, result.getCursorId());
-        assertFalse("This is a failure response, no more batches", result.hasMoreBatches());
-        assertEquals("application/json; charset=UTF-8", getMoreConn.getContentType());
-    }
-
-    private String executeQuery(Gson gson, Query<TestClass> mockMongoQuery,
-            Type typeToken, WebPreparedStatement<TestClass> stmt, boolean moreBatches)
-            throws MalformedURLException, IOException, ProtocolException {
-        URL url = new URL(getEndpoint() + "/query-execute");
-        HttpURLConnection queryExecuteConn = (HttpURLConnection) url.openConnection();
-        queryExecuteConn.setRequestMethod("POST");
-        sendAuthentication(queryExecuteConn, "ignored1", "ignored2");
-        queryExecuteConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        queryExecuteConn.setDoInput(true);
-        queryExecuteConn.setDoOutput(true);
-        
-        OutputStreamWriter out = new OutputStreamWriter(queryExecuteConn.getOutputStream());
-        String body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class);
-        out.write(body + "\n");
-        out.flush();
-
-        String cookieValue = queryExecuteConn.getHeaderField("Set-Cookie");
-        InputStreamReader in = new InputStreamReader(queryExecuteConn.getInputStream());
-        WebQueryResponse<TestClass> result = gson.fromJson(in, typeToken);
-        assertEquals("Expected more batches", moreBatches, result.hasMoreBatches());
-        TestClass[] results = result.getResultList();
-        assertEquals(2, results.length);
-        assertEquals("fluff1", results[0].getKey1());
-        assertEquals(42, results[0].getKey2());
-        assertEquals("fluff2", results[1].getKey1());
-        assertEquals(43, results[1].getKey2());
-
-        assertEquals("application/json; charset=UTF-8", queryExecuteConn.getContentType());
-        verify(mockMongoQuery).execute();
-        verify(mockMongoQuery).getWhereExpression();
-        verifyNoMoreInteractions(mockMongoQuery);
-        return cookieValue;
-    }
-    
-    private static class TrustedPreparedQueryTestResult {
-        
-        private final Gson gson;
-        private final Query<TestClass> mockMongoQuery;
-        private final Cursor<TestClass> cursor;
-        private final SharedStateId stmtId;
-        
-        private TrustedPreparedQueryTestResult(Gson gson, Query<TestClass> mockMongoQuery, Cursor<TestClass> cursor, SharedStateId stmtId) {
-            this.cursor = cursor;
-            this.gson = gson;
-            this.mockMongoQuery = mockMongoQuery;
-            this.stmtId = stmtId;
-        }
-    }
-    
-    @SuppressWarnings("unchecked")
-    private TrustedPreparedQueryTestResult prepareQuery(SharedStateId catId, String strDescriptor, boolean moreBatches) throws Exception {
-        TestClass expected1 = new TestClass();
-        expected1.setKey1("fluff1");
-        expected1.setKey2(42);
-        TestClass expected2 = new TestClass();
-        expected2.setKey1("fluff2");
-        expected2.setKey2(43);
-        // prepare-statement does this under the hood
-        Query<TestClass> mockMongoQuery = mock(Query.class);
-        when(mockStorage.createQuery(eq(category))).thenReturn(mockMongoQuery);
-
-        Cursor<TestClass> cursor = mock(Cursor.class);
-        WebStorageEndPoint.DEFAULT_QUERY_BATCH_SIZE = 2;
-        // Assuming: moreBatches == true then we have
-        // WebStorageEndpoint.getBatchFromCursor() method calls hasNext() twice,
-        // CursorManager.put() calls it once and WebStorageEndpoint.queryExecute()
-        // calls it once. Thus, 2 + 1 + 1 = 4 x true, then return false;
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(moreBatches).thenReturn(moreBatches).thenReturn(false);
-        when(cursor.next()).thenReturn(expected1).thenReturn(expected2);
-        
-        PreparedStatement<TestClass> mockPreparedQuery = mock(PreparedStatement.class);
-        when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery);
-        
-        ParsedStatement<TestClass> mockParsedStatement = mock(ParsedStatement.class);
-        when(mockParsedStatement.getNumParams()).thenReturn(1);
-        when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery);
-        when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement);
-        
-        // The web layer
-        when(mockPreparedQuery.executeQuery()).thenReturn(cursor);
-        // And the mongo layer
-        when(mockMongoQuery.execute()).thenReturn(cursor);
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/prepare-statement");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, "ignored1", "ignored2");
-        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        conn.setDoInput(true);
-        conn.setDoOutput(true);
-        Gson gson = new GsonBuilder()
-                            .registerTypeAdapterFactory(new PojoTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory())
-                            .create();
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId);
-        out.write(body + "\n");
-        out.flush();
-
-        Reader in = new InputStreamReader(conn.getInputStream());
-        WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class);
-        assertEquals(1, response.getNumFreeVariables());
-        assertEquals(0, response.getStatementId().getId());
-        assertEquals("application/json; charset=UTF-8", conn.getContentType());
-        
-        return new TrustedPreparedQueryTestResult(gson, mockMongoQuery, cursor, response.getStatementId());
-    }
-
-    private String setupPreparedQueryWithTrustedDescriptor() throws Exception {
-        String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42";
-        // metadata which basically does no filtering. There's another test which
-        // asserts only allowed data (via ACL) gets returned.
-        setupTrustedStatementRegistry(strDescriptor);
-        
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY));
-        roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT));
-        roles.add(new RolePrincipal(Roles.READ));
-        roles.add(new RolePrincipal(Roles.ACCESS_REALM));
-        UserPrincipal testUser = new UserPrincipal("ignored1");
-        testUser.setRoles(roles);
-        
-        final JAASLoginService loginService = getConfiguredLoginService(testUser, roles);
-        
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        // This makes register category work for the "test" category.
-        // Undone via @After
-        setupTrustedCategory(categoryName);
-        return strDescriptor;
-    }
-    
-    /*
-     * 
-     * This test simulates a case where the mongo query would return more than
-     * a user can see. In this case only records matching agentIds which are
-     * allowed via roles should get returned.
-     */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Test
-    public void authorizedFilteredQuery() throws Exception {
-        Category oldCategory = category;
-        String categoryName = "test-authorizedFilteredQuery";
-        // redefine category to include the agentId key in the category.
-        // undone via a the try-finally block.
-        category = new Category(categoryName, TestClass.class, key1, key2, Key.AGENT_ID);
-        try {
-            String strDescriptor = "QUERY " + category.getName() + " WHERE '" +
-                    key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42";
-            setupTrustedStatementRegistry(strDescriptor);
-            
-            Set<BasicRole> roles = new HashSet<>();
-            roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY));
-            roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT));
-            roles.add(new RolePrincipal(Roles.READ));
-            roles.add(new RolePrincipal(Roles.ACCESS_REALM));
-            String fakeAgentId = "someAgentId";
-            roles.add(new RolePrincipal("thermostat-agents-grant-read-agentId-" + fakeAgentId));
-            UserPrincipal testUser = new UserPrincipal("ignored1");
-            testUser.setRoles(roles);
-            
-            final JAASLoginService loginService = getConfiguredLoginService(testUser, roles);
-            port = FreePortFinder.findFreePort(new TryPort() {
-                
-                @Override
-                public void tryPort(int port) throws Exception {
-                    startServer(port, loginService);
-                }
-            });
-            // This makes register category work for the "test" category.
-            // Undone via @After
-            setupTrustedCategory(categoryName);
-            SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2");
-            
-            TestClass expected1 = new TestClass();
-            expected1.setKey1("fluff1");
-            expected1.setKey2(42);
-            TestClass expected2 = new TestClass();
-            expected2.setKey1("fluff2");
-            expected2.setKey2(43);
-            // prepare-statement does this under the hood
-            Query<TestClass> mockMongoQuery = mock(Query.class);
-            
-            when(mockStorage.createQuery(eq(category))).thenReturn(mockMongoQuery);
-    
-            Cursor<TestClass> cursor = mock(Cursor.class);
-            when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-            when(cursor.next()).thenReturn(expected1).thenReturn(expected2);
-            
-            PreparedStatement mockPreparedQuery = mock(PreparedStatement.class);
-            when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery);
-            
-            ParsedStatement mockParsedStatement = mock(ParsedStatement.class);
-            when(mockParsedStatement.getNumParams()).thenReturn(1);
-            when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery);
-            when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement);
-            
-            // The web layer
-            when(mockPreparedQuery.executeQuery()).thenReturn(cursor);
-            // And the mongo layer
-            when(mockMongoQuery.execute()).thenReturn(cursor);
-    
-            String endpoint = getEndpoint();
-            URL url = new URL(endpoint + "/prepare-statement");
-            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-            conn.setRequestMethod("POST");
-            sendAuthentication(conn, "ignored1", "ignored2");
-            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-            conn.setDoInput(true);
-            conn.setDoOutput(true);
-            Gson gson = new GsonBuilder()
-                                .registerTypeAdapterFactory(new PojoTypeAdapterFactory())
-                                .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory())
-                                .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory())
-                                .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory())
-                                .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory())
-                                .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory())
-                                .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory())
-                                .create();
-            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-            String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId);
-            out.write(body + "\n");
-            out.flush();
-    
-            Reader in = new InputStreamReader(conn.getInputStream());
-            WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class);
-            assertEquals(1, response.getNumFreeVariables());
-            assertEquals(0, response.getStatementId().getId());
-            assertEquals("application/json; charset=UTF-8", conn.getContentType());
-            
-            
-            
-            // now execute the query we've just prepared
-            WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(1, response.getStatementId());
-            stmt.setString(0, "fluff");
-            
-            url = new URL(endpoint + "/query-execute");
-            HttpURLConnection conn2 = (HttpURLConnection) url.openConnection();
-            conn2.setRequestMethod("POST");
-            sendAuthentication(conn2, "ignored1", "ignored2");
-            conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-            conn2.setDoInput(true);
-            conn2.setDoOutput(true);
-            
-            out = new OutputStreamWriter(conn2.getOutputStream());
-            body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class);
-            out.write(body + "\n");
-            out.flush();
-    
-            in = new InputStreamReader(conn2.getInputStream());
-            Type typeToken = new TypeToken<WebQueryResponse<TestClass>>(){}.getType();
-            WebQueryResponse<TestClass> result = gson.fromJson(in, typeToken);
-            TestClass[] results = result.getResultList();
-            assertEquals(2, results.length);
-            assertEquals("fluff1", results[0].getKey1());
-            assertEquals(42, results[0].getKey2());
-            assertEquals("fluff2", results[1].getKey1());
-            assertEquals(43, results[1].getKey2());
-    
-            assertEquals("application/json; charset=UTF-8", conn2.getContentType());
-            verify(mockMongoQuery).execute();
-            verify(mockMongoQuery).getWhereExpression();
-            ArgumentCaptor<Expression> expressionCaptor = ArgumentCaptor.forClass(Expression.class);
-            verify(mockMongoQuery).where(expressionCaptor.capture());
-            verifyNoMoreInteractions(mockMongoQuery);
-            
-            Expression capturedExpression = expressionCaptor.getValue();
-            assertTrue(capturedExpression instanceof BinarySetMembershipExpression);
-            Set<String> agentIds = new HashSet<>();
-            agentIds.add(fakeAgentId);
-            Expression expectedExpression = new ExpressionFactory().in(Key.AGENT_ID, agentIds, String.class);
-            assertEquals(expectedExpression, capturedExpression);
-        } finally {
-            category = oldCategory; 
-        }
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Test
-    public void authorizedPreparedAggregateQuery() throws Exception {
-        String strDescriptor = "QUERY-COUNT " + category.getName();
-        setupTrustedStatementRegistry(strDescriptor);
-        
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY));
-        roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT));
-        roles.add(new RolePrincipal(Roles.READ));
-        roles.add(new RolePrincipal(Roles.ACCESS_REALM));
-        UserPrincipal testUser = new UserPrincipal("ignored1");
-        testUser.setRoles(roles);
-        
-        final JAASLoginService loginService = getConfiguredLoginService(testUser, roles);
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        
-        AggregateCount count = new AggregateCount();
-        count.setCount(500);
-        // prepare-statement does this under the hood
-        AggregateQuery<AggregateCount> mockMongoQuery = mock(AggregateQuery.class);
-        Category<AggregateCount> adapted = new CategoryAdapter(category).getAdapted(AggregateCount.class);
-        SharedStateId catId = registerCategoryAndGetId(adapted, "no-matter", "no-matter");
-        when(mockStorage.createAggregateQuery(eq(AggregateFunction.COUNT), eq(adapted))).thenReturn(mockMongoQuery);
-
-        Cursor<AggregateCount> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(count);
-        
-        PreparedStatement mockPreparedQuery = mock(PreparedStatement.class);
-        when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery);
-        
-        ParsedStatement mockParsedStatement = mock(ParsedStatement.class);
-        when(mockParsedStatement.getNumParams()).thenReturn(0);
-        when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery);
-        when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement);
-        
-        // The web layer
-        when(mockPreparedQuery.executeQuery()).thenReturn(cursor);
-        // And the mongo layer
-        when(mockMongoQuery.execute()).thenReturn(cursor);
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/prepare-statement");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, "no-matter", "no-matter");
-        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        conn.setDoInput(true);
-        conn.setDoOutput(true);
-        Gson gson = new GsonBuilder()
-                            .registerTypeAdapterFactory(new PojoTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory())
-                            .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory())
-                            .create();
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId);
-        out.write(body + "\n");
-        out.flush();
-
-        Reader in = new InputStreamReader(conn.getInputStream());
-        WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class);
-        assertEquals(0, response.getNumFreeVariables());
-        assertEquals(0, response.getStatementId().getId());
-        assertEquals("application/json; charset=UTF-8", conn.getContentType());
-        
-        
-        
-        // now execute the query we've just prepared
-        WebPreparedStatement<AggregateCount> stmt = new WebPreparedStatement<>(0, response.getStatementId());
-        
-        url = new URL(endpoint + "/query-execute");
-        HttpURLConnection conn2 = (HttpURLConnection) url.openConnection();
-        conn2.setRequestMethod("POST");
-        sendAuthentication(conn2, "no-matter", "no-matter");
-        conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        conn2.setDoInput(true);
-        conn2.setDoOutput(true);
-        
-        out = new OutputStreamWriter(conn2.getOutputStream());
-        body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class);
-        out.write(body + "\n");
-        out.flush();
-
-        in = new InputStreamReader(conn2.getInputStream());
-        Type typeToken = new TypeToken<WebQueryResponse<AggregateCount>>(){}.getType();
-        WebQueryResponse<AggregateCount> result = gson.fromJson(in, typeToken);
-        AggregateCount[] results = result.getResultList();
-        assertEquals(1, results.length);
-        assertEquals(500, results[0].getCount());
-
-        assertEquals("application/json; charset=UTF-8", conn2.getContentType());
-        verify(mockMongoQuery).execute();
-        verify(mockMongoQuery).getWhereExpression();
-        verifyNoMoreInteractions(mockMongoQuery);
-    }
-    
-    private void setupTrustedCategory(String categoryName) {
-        Set<String> descs = new HashSet<>();
-        descs.add(categoryName);
-        CategoryRegistration reg = mock(CategoryRegistration.class);
-        when(reg.getCategoryNames()).thenReturn(descs);
-        List<CategoryRegistration> regs = new ArrayList<>(1);
-        regs.add(reg);
-        KnownCategoryRegistry registry = new KnownCategoryRegistry(regs);
-        KnownCategoryRegistryFactory.setInstance(registry);
-    }
-    
-    private void setupTrustedStatementRegistry(String strDescriptor) {
-        Set<String> descs = new HashSet<>();
-        descs.add(strDescriptor);
-        StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration(descs);
-        List<StatementDescriptorRegistration> regs = new ArrayList<>(1);
-        regs.add(reg);
-        KnownDescriptorRegistry registry = new KnownDescriptorRegistry(regs);
-        KnownDescriptorRegistryFactory.setKnownDescriptorRegistry(registry);
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void authorizedPreparedWrite() throws Exception {
-        Category<TestClass> oldCategory = category;
-        String categoryName = "test-authorizedPreparedWrite";
-        // redefine category to include the agentId key in the category.
-        // undone via a the try-finally block.
-        category = new Category<>(categoryName, TestClass.class, key1, key2, Key.AGENT_ID);
-        try {
-            String strDescriptor = "ADD " + category.getName() + " SET '" +
-                    key1.getName() + "' = ?s , '" + key2.getName() + "' = ?s";
-            setupTrustedStatementRegistry(strDescriptor);
-            
-            Set<BasicRole> roles = new HashSet<>();
-            roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY));
-            roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT));
-            roles.add(new RolePrincipal(Roles.WRITE));
-            roles.add(new RolePrincipal(Roles.ACCESS_REALM));
-            UserPrincipal testUser = new UserPrincipal("ignored1");
-            testUser.setRoles(roles);
-            
-            final JAASLoginService loginService = getConfiguredLoginService(testUser, roles);
-            port = FreePortFinder.findFreePort(new TryPort() {
-                
-                @Override
-                public void tryPort(int port) throws Exception {
-                    startServer(port, loginService);
-                }
-            });
-            // This makes register category work for the "test" category.
-            // Undone via @After
-            setupTrustedCategory(categoryName);
-            SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2");
-            
-            // prepare-statement does this under the hood
-            Add<TestClass> mockMongoAdd = mock(Add.class);
-            
-            when(mockStorage.createAdd(eq(category))).thenReturn(mockMongoAdd);
-    
-            PreparedStatement<TestClass> mockPreparedQuery = mock(PreparedStatement.class);
-            when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery);
-            
-            ParsedStatement<TestClass> mockParsedStatement = mock(ParsedStatement.class);
-            when(mockParsedStatement.getNumParams()).thenReturn(2);
-            when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoAdd);
-            when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement);
-            
-            // The web layer
-            when(mockPreparedQuery.execute()).thenReturn(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE);
-            // And the mongo layer
-            when(mockMongoAdd.apply()).thenReturn(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE);
-    
-            String endpoint = getEndpoint();
-            URL url = new URL(endpoint + "/prepare-statement");
-            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-            conn.setRequestMethod("POST");
-            sendAuthentication(conn, "ignored1", "ignored2");
-            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-            conn.setDoInput(true);
-            conn.setDoOutput(true);
-            Gson gson = new GsonBuilder()
-                .registerTypeAdapterFactory(new PojoTypeAdapterFactory())
-                .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory())
-                .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory())
-                .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory())
-                .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory())
-                .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory())
-                .create();
-            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-            String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId);
-            out.write(body + "\n");
-            out.flush();
-    
-            Reader in = new InputStreamReader(conn.getInputStream());
-            WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class);
-            assertEquals(2, response.getNumFreeVariables());
-            assertEquals(0, response.getStatementId().getId());
-            assertEquals("application/json; charset=UTF-8", conn.getContentType());
-            
-            
-            
-            // now execute the ADD we've just prepared
-            WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(2, response.getStatementId());
-            stmt.setString(0, "fluff");
-            stmt.setString(1, "test2");
-            
-            url = new URL(endpoint + "/write-execute");
-            HttpURLConnection conn2 = (HttpURLConnection) url.openConnection();
-            conn2.setRequestMethod("POST");
-            sendAuthentication(conn2, "ignored1", "ignored2");
-            conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-            conn2.setDoInput(true);
-            conn2.setDoOutput(true);
-            
-            out = new OutputStreamWriter(conn2.getOutputStream());
-            body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class);
-            out.write(body + "\n");
-            out.flush();
-    
-            in = new InputStreamReader(conn2.getInputStream());
-            int result = gson.fromJson(in, int.class);
-            assertEquals(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE, result);
-        } finally {
-            category = oldCategory; 
-        }
-    }
-    
-    private String getURLEncodedCategoryIdJson(Gson gson, SharedStateId catId) throws UnsupportedEncodingException {
-        return URLEncoder.encode(gson.toJson(catId), "UTF-8");
-    }
-    
-    @Test
-    public void cannotRegisterCategoryWithoutRegistrationOnInit() throws Exception {
-        // need this in order to pass basic permissions.
-        String[] roleNames = new String[] {
-                Roles.REGISTER_CATEGORY
-        };
-        String username = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(username, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        try {
-            String endpoint = getEndpoint();
-            URL url = new URL(endpoint + "/register-category");
-            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-            String enc = "UTF-8";
-            conn.setRequestProperty("Content-Encoding", enc);
-            conn.setDoOutput(true);
-            conn.setDoInput(true);
-            conn.setRequestMethod("POST");
-            sendAuthentication(conn, username, password);
-            OutputStream out = conn.getOutputStream();
-            Gson gson = new Gson();
-            OutputStreamWriter writer = new OutputStreamWriter(out);
-            writer.write("name=");
-            writer.write(URLEncoder.encode(category.getName(), enc));
-            writer.write("&category=");
-            writer.write(URLEncoder.encode(gson.toJson(category), enc));
-            writer.flush();
-
-            // "test" category name not registered, expecting forbidden.
-            assertEquals(HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode());
-        } catch (IOException e) {
-            fail("Should not throw exception! " + e.getMessage());
-        }
-    }
-
-    @Test
-    public void unauthorizedPrepareStmt() throws Exception {
-        String failMsg = "thermostat-prepare-statement role missing, expected Forbidden!";
-        doUnauthorizedTest("prepare-statement", failMsg);
-    }
-    
-    @Test
-    public void unauthorizedExecutePreparedQuery() throws Exception {
-        String failMsg = "thermostat-read role missing, expected Forbidden!";
-        doUnauthorizedTest("query-execute", failMsg);
-    }
-    
-    private void doUnauthorizedTest(String pathForEndPoint, String failMessage) throws Exception {
-        String[] insufficientRoleNames = new String[] {
-                Roles.REGISTER_CATEGORY,
-                Roles.ACCESS_REALM
-        };
-        doUnauthorizedTest(pathForEndPoint, failMessage, insufficientRoleNames, true);
-    }
-
-    private void doUnauthorizedTest(String pathForEndPoint, String failMessage,
-            String[] insufficientRoles, boolean doRegisterCategory) throws Exception,
-            MalformedURLException, IOException, ProtocolException {
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, insufficientRoles); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        if (doRegisterCategory) {
-            // This makes register category work for the "test" category.
-            // Undone via @After
-            setupTrustedCategory(categoryName);
-            registerCategoryAndGetId(category, testuser, password);
-        }
-        
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/" + pathForEndPoint);
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        
-        assertEquals(failMessage, HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode());
-    }
-    
-    @Test
-    public void authorizedRegisterCategoryTest() throws Exception {
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY));
-        roles.add(new RolePrincipal(Roles.ACCESS_REALM));
-        UserPrincipal testUser = new UserPrincipal("ignored1");
-        testUser.setRoles(roles);
-        
-        final JAASLoginService loginService = getConfiguredLoginService(testUser, roles);
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        Category<HostInfo> wantedCategory = HostInfoDAO.hostInfoCategory;
-        Category<AggregateCount> aggregate = new CategoryAdapter<HostInfo, AggregateCount>(wantedCategory).getAdapted(AggregateCount.class);
-        
-        // First the originating category has to be registered, then the adapted
-        // one.
-        SharedStateId realId = registerCategoryAndGetId(wantedCategory, "no-matter", "no-matter");
-        SharedStateId aggregateId = registerCategoryAndGetId(aggregate, "no-matter", "no-matter");
-        
-        assertTrue("Aggregate categories need their own ID", realId.getId() != aggregateId.getId());
-        
-        verify(mockStorage).registerCategory(eq(wantedCategory));
-        verifyNoMoreInteractions(mockStorage);
-    }
-    
-    private SharedStateId registerCategoryAndGetId(Category<?> cat, String username, String password) throws Exception {
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/register-category");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, username, password);
-
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        Gson gson = new GsonBuilder().registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()).create();
-        out.write("name=" + cat.getName() + "&data-class=" + cat.getDataClass().getName() + "&category=" + gson.toJson(cat));
-        out.flush();
-        assertEquals(200, conn.getResponseCode());
-        Reader reader = new InputStreamReader(conn.getInputStream());
-        SharedStateId id = gson.fromJson(reader, SharedStateId.class);
-        return id;
-    }
-    
-    private void setCookie(HttpURLConnection conn, String cookieVal) {
-        conn.setRequestProperty("Cookie", cookieVal);
-    }
-
-    private void sendAuthentication(HttpURLConnection conn, String username, String passwd) {
-        String userpassword = username + ":" + passwd;
-        String encodedAuthorization = Base64.encodeBase64String(userpassword.getBytes());
-        conn.setRequestProperty("Authorization", "Basic "+ encodedAuthorization);
-    }
-
-    @Test
-    public void authorizedSaveFile() throws Exception {
-        String filename = "fluff";
-        String[] roleNames = new String[] {
-                Roles.SAVE_FILE,
-                Roles.ACCESS_REALM,
-                // User also needs permission for specific file to be saved.
-                WebStorageEndPoint.FILES_WRITE_GRANT_ROLE_PREFIX + filename
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        String endpoint = getEndpoint();
-
-        URL url = new URL(endpoint + "/save-file");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=fluff");
-        conn.setRequestProperty("Transfer-Encoding", "chunked");
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("--fluff\r\n");
-        out.write("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n");
-        out.write("Content-Type: application/octet-stream\r\n");
-        out.write("Content-Transfer-Encoding: binary\r\n");
-        out.write("\r\n");
-        out.write("Hello World\r\n");
-        out.write("--fluff--\r\n");
-        out.flush();
-        // needed in order to trigger inCaptor interaction with mock
-        int respCode = conn.getResponseCode();
-        assertEquals(HttpServletResponse.SC_OK, respCode);
-        ArgumentCaptor<InputStream> inCaptor = ArgumentCaptor.forClass(InputStream.class);
-        verify(mockStorage).saveFile(eq(filename), inCaptor.capture(), isA(CloseOnSave.class));
-        InputStream in = inCaptor.getValue();
-        byte[] data = new byte[11];
-        int totalRead = 0;
-        while (totalRead < 11) {
-            int read = in.read(data, totalRead, 11 - totalRead);
-            if (read < 0) {
-                fail();
-            }
-            totalRead += read;
-        }
-        assertEquals("Hello World", new String(data));
-    }
-    
-    @Test
-    public void unauthorizedSaveFile() throws Exception {
-        String failMsg = "thermostat-save-file role missing, expected Forbidden!";
-        String[] insufficientRoles = new String[] {
-                Roles.ACCESS_REALM
-        };
-        doUnauthorizedTest("save-file", failMsg, insufficientRoles, false);
-    }
-    
-    @Test
-    public void unauthorizedSaveFileMissingSpecificRole() throws Exception {
-        String filename = "foo.txt";
-        String[] insufficientRoles = new String[] {
-                Roles.SAVE_FILE,
-                Roles.ACCESS_REALM
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, insufficientRoles); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        String endpoint = getEndpoint();
-
-        URL url = new URL(endpoint + "/save-file");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=fluff");
-        conn.setRequestProperty("Transfer-Encoding", "chunked");
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("--fluff\r\n");
-        out.write("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n");
-        out.write("Content-Type: application/octet-stream\r\n");
-        out.write("Content-Transfer-Encoding: binary\r\n");
-        out.write("\r\n");
-        out.write("Hello World\r\n");
-        out.write("--fluff--\r\n");
-        out.flush();
-        int respCode = conn.getResponseCode();
-        assertEquals(HttpServletResponse.SC_FORBIDDEN, respCode);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void authorizedLoadFile() throws Exception {
-        String filename = "fluff";
-        String[] roleNames = new String[] {
-                Roles.LOAD_FILE,
-                Roles.ACCESS_REALM,
-                // Grant the specific read file permission
-                WebStorageEndPoint.FILES_READ_GRANT_ROLE_PREFIX + filename
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        
-        byte[] data = "Hello World".getBytes();
-        InputStream in = new ByteArrayInputStream(data);
-        when(mockStorage.loadFile(filename)).thenReturn(in);
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/load-file");
-
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("file=" + filename);
-        out.flush();
-        int respCode = conn.getResponseCode();
-        assertEquals(HttpServletResponse.SC_OK, respCode);
-        in = conn.getInputStream();
-        data = new byte[11];
-        int totalRead = 0;
-        while (totalRead < 11) {
-            int read = in.read(data, totalRead, 11 - totalRead);
-            if (read < 0) {
-                fail();
-            }
-            totalRead += read;
-        }
-        assertEquals("Hello World", new String(data));
-        verify(mockStorage).loadFile(filename);
-    }
-    
-    @Test
-    public void unauthorizedLoadFile() throws Exception {
-        String failMsg = "thermostat-load-file role missing, expected Forbidden!";
-        String[] insufficientRoles = new String[] {
-                Roles.ACCESS_REALM
-        };
-        doUnauthorizedTest("load-file", failMsg, insufficientRoles, false);
-    }
-    
-    @Test
-    public void unauthorizedLoadFileMissingSpecificRole() throws Exception {
-        String filename = "foo.txt";
-        String[] insufficientRoles = new String[] {
-                Roles.LOAD_FILE,
-                Roles.ACCESS_REALM
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, insufficientRoles); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        
-        byte[] data = "Hello World".getBytes();
-        InputStream in = new ByteArrayInputStream(data);
-        when(mockStorage.loadFile(filename)).thenReturn(in);
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/load-file");
-
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("file=" + filename);
-        out.flush();
-        int respCode = conn.getResponseCode();
-        assertEquals(HttpServletResponse.SC_FORBIDDEN, respCode);
-        verifyNoMoreInteractions(mockStorage);
-    }
-
-    @Test
-    public void authorizedPurge() throws Exception {
-        String[] roleNames = new String[] {
-                Roles.PURGE,
-                Roles.ACCESS_REALM
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/purge");
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setDoOutput(true);
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.getOutputStream().write("agentId=fluff".getBytes());
-        int status = conn.getResponseCode();
-        assertEquals(HttpServletResponse.SC_OK, status);
-        verify(mockStorage).purge("fluff");
-    }
-    
-    @Test
-    public void unauthorizedAccessRealm() throws Exception {
-        String failMsg = Roles.ACCESS_REALM + " role missing, expected Forbidden!";
-        String[] insufficientRoles = new String[0];
-        // entry point for this test doesn't matter. Use '/'. 
-        doUnauthorizedTest("", failMsg, insufficientRoles, false);
-    }
-    
-    @Test
-    public void authorizedAccessRealm() throws Exception {
-        String[] roles = new String[] {
-                Roles.ACCESS_REALM
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roles); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/"); // Testing the realm, nothing else.
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, testuser, password);
-        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        
-        assertEquals(HttpServletResponse.SC_OK, conn.getResponseCode());
-    }
-    
-    @Test
-    public void unauthorizedPurge() throws Exception {
-        String failMsg = "thermostat-purge role missing, expected Forbidden!";
-        String[] insufficientRoles = new String[] {
-                Roles.ACCESS_REALM
-        };
-        doUnauthorizedTest("purge", failMsg, insufficientRoles, false);
-    }
-
-    private String getEndpoint() {
-        return "http://localhost:" + port + "/storage";
-    }
-
-    @Test
-    public void authorizedGenerateToken() throws Exception {
-        String actionName = "testing";
-        String[] roleNames = new String[] {
-                Roles.CMD_CHANNEL_GENERATE,
-                Roles.ACCESS_REALM,
-                // grant the "testing" action
-                WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        verifyAuthorizedGenerateToken(testuser, password, actionName);
-    }
-
-    @Test
-    public void unauthorizedGenerateToken() throws Exception {
-        String failMsg = "thermostat-cmdc-generate role missing, expected Forbidden!";
-        String[] insufficientRoles = new String[] {
-                Roles.ACCESS_REALM
-        };
-        doUnauthorizedTest("generate-token", failMsg, insufficientRoles, false);
-    }
-
-    @Test
-    public void authorizedGenerateVerifyToken() throws Exception {
-        String actionName = "someAction";
-        String[] roleNames = new String[] {
-                Roles.CMD_CHANNEL_GENERATE,
-                Roles.CMD_CHANNEL_VERIFY,
-                Roles.ACCESS_REALM,
-                // grant "someAction" to be performed
-                WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName,
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        byte[] token = verifyAuthorizedGenerateToken(testuser, password, actionName);
-        
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/verify-token");
-        
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("client-token=fluff&action-name=" + actionName + "&token=" +
-                URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8"));
-        out.flush();
-        assertEquals(200, conn.getResponseCode());
-    }
-    
-    @Test
-    public void unAuthorizedGenerateVerifyToken() throws Exception {
-        String testuser = "testuser";
-        String password = "testpassword";
-        String actionName = "someAction";
-        String[] roleNames = new String[] {
-                Roles.CMD_CHANNEL_GENERATE,
-                Roles.CMD_CHANNEL_VERIFY,
-                Roles.ACCESS_REALM,
-                // missing the thermostat-cmdc-grant-someAction role
-        };
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        
-        byte[] result = verifyAuthorizedGenerateToken(testuser, password, actionName, 403);
-        assertNull(result);
-    }
-    
-    @Test
-    public void authenticatedGenerateVerifyTokenWithActionNameMismatch() throws Exception {
-        String actionName = "someAction";
-        String[] roleNames = new String[] {
-                Roles.CMD_CHANNEL_GENERATE,
-                WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName,
-                Roles.CMD_CHANNEL_VERIFY,
-                Roles.ACCESS_REALM
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        byte[] token = verifyAuthorizedGenerateToken(testuser, password, actionName);
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/verify-token");
-
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        // expected action-name parameter is "someAction". This should not
-        // verify => 403.
-        out.write("client-token=fluff&action-name=wrongAction&token=" + URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8"));
-        out.flush();
-        assertEquals(403, conn.getResponseCode());
-    }
-    
-
-    @Test
-    public void authenticatedTokenTimeout() throws Exception {
-        String actionName = "someAction";
-        String[] roleNames = new String[] {
-                Roles.CMD_CHANNEL_GENERATE,
-                Roles.CMD_CHANNEL_VERIFY,
-                Roles.ACCESS_REALM,
-                // Grant "someAction", this test tests the time-out
-                WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        byte[] token = verifyAuthorizedGenerateToken(testuser, password, actionName);
-
-        Thread.sleep(700); // Timeout is set to 500ms for tests, 700ms should be enough for everybody. ;-)
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/verify-token");
-
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("client-token=fluff&action-name=" + actionName + "&token=" +
-                  URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8"));
-        out.flush();
-        assertEquals(403, conn.getResponseCode());
-    }
-
-    @Test
-    public void authenticatedVerifyNonExistentToken() throws Exception {
-        String[] roleNames = new String[] {
-                Roles.CMD_CHANNEL_VERIFY,
-                Roles.ACCESS_REALM
-        };
-        String testuser = "testuser";
-        String password = "testpassword";
-        final LoginService loginService = new TestLoginService(testuser, password, roleNames); 
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port, loginService);
-            }
-        });
-        
-        byte[] token = "fluff".getBytes();
-
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/verify-token");
-
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
-        sendAuthentication(conn, testuser, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("client-token=fluff&action-name=someAction&token=" + URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8"));
-        out.flush();
-        assertEquals(403, conn.getResponseCode());
-    }
-    
-    @Test
-    public void unauthorizedVerifyToken() throws Exception {
-        String failMsg = "thermostat-cmdc-verify role missing, expected Forbidden!";
-        String[] insufficientRoles = new String[] {
-                Roles.ACCESS_REALM
-        };
-        doUnauthorizedTest("verify-token", failMsg, insufficientRoles, false);
-    }
-    
-    private byte[] verifyAuthorizedGenerateToken(String username, String password, String actionName) throws IOException {
-        return verifyAuthorizedGenerateToken(username, password, actionName, 200);
-    }
-    
-    private byte[] verifyAuthorizedGenerateToken(String username, String password, String actionName, int expectedResponseCode) throws IOException {
-        return verifyAuthorizedGenerateToken(username, password, expectedResponseCode, actionName);
-    }
-    
-    private JAASLoginService getConfiguredLoginService(UserPrincipal user, Set<BasicRole> roles) {
-        Configuration config = new TestConfiguration(user, roles);
-        Configuration.setConfiguration(config);
-        JAASLoginService loginService = new JAASLoginService("foo");
-        loginService.setRoleClassNames(new String[] { RolePrincipal.class.getName() });
-        return loginService;
-    }
-    
-    private byte[] verifyAuthorizedGenerateToken(String username,
-            String password, int expectedResponseCode, String actionName)
-            throws IOException {
-        String endpoint = getEndpoint();
-        URL url = new URL(endpoint + "/generate-token");
-
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setRequestMethod("POST");
-        sendAuthentication(conn, username, password);
-        conn.setDoOutput(true);
-        conn.setDoInput(true);
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        out.write("client-token=fluff&action-name=" + actionName);
-        out.flush();
-        int actualResponseCode = conn.getResponseCode();
-        assertEquals(expectedResponseCode, actualResponseCode);
-        if (actualResponseCode == 200) {
-            InputStream in = conn.getInputStream();
-            int length = conn.getContentLength();
-            byte[] token = new byte[length];
-            assertEquals(256, length);
-            int totalRead = 0;
-            while (totalRead < length) {
-                int read = in.read(token, totalRead, length - totalRead);
-                if (read < 0) {
-                    fail();
-                }
-                totalRead += read;
-            }
-            return token;
-        } else {
-            return null;
-        }
-    }
-    
-    private static class TestLoginService extends MappedLoginService {
-
-        private final String[] roleNames;
-        private final String username;
-        private final String password;
-
-        private TestLoginService(String username, String password,
-                String[] roleNames) {
-            this.username = username;
-            this.password = password;
-            this.roleNames = roleNames;
-        }
-
-        @Override
-        protected void loadUsers() throws IOException {
-            putUser(username, new Password(password),
-                    roleNames);
-        }
-
-        @Override
-        protected UserIdentity loadUser(String username) {
-            return new DefaultUserIdentity(null, null,
-                    roleNames);
-        }
-    }
-    
-    private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration {
-
-        private final Set<String> descriptorSet;
-        private TestStatementDescriptorRegistration(Set<String> descriptorSet) {
-            assertEquals(1, descriptorSet.size());
-            this.descriptorSet = descriptorSet;
-        }
-
-        @Override
-        public Set<String> getStatementDescriptors() {
-            return descriptorSet;
-        }
-        
-    }
-    
-    private class TestConfiguration extends Configuration {
-        
-        private final UserPrincipal uPrincipal;
-        private final Set<BasicRole> roles;
-        
-        TestConfiguration(UserPrincipal uPrincipal, Set<BasicRole> roles) {
-            this.uPrincipal = uPrincipal;
-            this.roles = roles;
-        }
-
-        @Override
-        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-            Map<String, Object> state = new HashMap<>();
-            // TestLoginModule uses those options
-            state.put("user", uPrincipal);
-            state.put("roles", roles);
-            AppConfigurationEntry entry = new AppConfigurationEntry(TestLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, state);
-            return new AppConfigurationEntry[] { entry };
-        }
-        
-    }
-    
-    public static class TestLoginModule implements LoginModule {
-        
-        private Subject subject;
-        private UserPrincipal user;
-        private Set<BasicRole> roles;
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public void initialize(Subject subject,
-                CallbackHandler callbackHandler, Map<String, ?> sharedState,
-                Map<String, ?> options) {
-            this.subject = subject;
-            this.user = (UserPrincipal)options.get("user");
-            this.roles = (Set<BasicRole>)options.get("roles");
-        }
-
-        @Override
-        public boolean login() throws LoginException {
-            Set<Principal> principals = subject.getPrincipals();
-            principals.add(user);
-            principals.addAll(roles);
-            return true;
-        }
-
-        @Override
-        public boolean commit() throws LoginException {
-            return true;
-        }
-
-        @Override
-        public boolean abort() throws LoginException {
-            return true;
-        }
-
-        @Override
-        public boolean logout() throws LoginException {
-            return true;
-        }
-        
-    }
-    
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebstorageEndpointTestUtils.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server;
-
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributes;
-
-public class WebstorageEndpointTestUtils {
-
-    static void deleteDirectoryRecursive(Path dir) throws IOException {
-        Files.walkFileTree(dir, new FileVisitor<Path>() {
-
-            @Override
-            public FileVisitResult preVisitDirectory(Path dir,
-                    BasicFileAttributes attrs) throws IOException {
-                // nothing
-                return FileVisitResult.CONTINUE;
-            }
-
-            @Override
-            public FileVisitResult visitFile(Path file,
-                    BasicFileAttributes attrs) throws IOException {
-                Files.delete(file);
-                return FileVisitResult.CONTINUE;
-            }
-
-            @Override
-            public FileVisitResult visitFileFailed(Path file, IOException exc)
-                    throws IOException {
-                exc.printStackTrace();
-                return FileVisitResult.CONTINUE;
-            }
-
-            @Override
-            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
-                    throws IOException {
-                // All files have been visitated before that.
-                Files.delete(dir);
-                return FileVisitResult.CONTINUE;
-            }
-            
-        });
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/AgentIdFilterTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinarySetMembershipExpression;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-public class AgentIdFilterTest {
-    
-    private static class FooPojo implements Pojo {
-        // Dummy class for testing
-    }
-    
-    private static final Category<FooPojo> TEST_NON_NULL_CATEGORY = new Category<>("foo-agentid-filter-test", FooPojo.class, Key.AGENT_ID);
-    private static final Category<FooPojo> TEST_NULL_CATEGORY = new Category<>("foo-agentid-filter-test-null", FooPojo.class);
-    /**
-     * A query descriptor which will return a non-null Key for the "vmId" name.
-     */
-    private static final StatementDescriptor<FooPojo> TEST_DESC_NON_NULL_AGENT_ID = new StatementDescriptor<>(TEST_NON_NULL_CATEGORY, "QUERY foo");
-    /**
-     * A query descriptor which will return a null Key for the "vmId" name.
-     */
-    private static final StatementDescriptor<FooPojo> TEST_DESC_NULL_AGENT_ID = new StatementDescriptor<>(TEST_NULL_CATEGORY, "QUERY foo-null");
-    
-    @Test
-    public void testReadAll() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal agentReadAll = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL);
-        roles.add(agentReadAll);
-        
-        AgentIdFilter<?> filter = new AgentIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertEquals(null, result.getFilterExpression());
-    }
-    
-    @Test
-    public void testReadAllAddToParent() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal agentReadAll = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL);
-        roles.add(agentReadAll);
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        AgentIdFilter<?> filter = new AgentIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-    
-    @Test
-    public void addsAgentIdInQuery() {
-        String agentId = UUID.randomUUID().toString();
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        roles.add(agent1Role);
-        AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles);
-        // returning non-null agent id key will work
-        FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_AGENT_ID, null);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinarySetMembershipExpression);
-        Set<String> agentIdSet = new HashSet<>();
-        agentIdSet.add(agentId);
-        Expression expected = new ExpressionFactory().in(Key.AGENT_ID, agentIdSet, String.class);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void addsAgentIdInQueryToParentExpression() {
-        String agentId = UUID.randomUUID().toString();
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        roles.add(agent1Role);
-        AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_AGENT_ID, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinaryLogicalExpression);
-        Set<String> agentIdSet = new HashSet<>();
-        agentIdSet.add(agentId);
-        Expression expectedIn = factory.in(Key.AGENT_ID, agentIdSet, String.class);
-        Expression expected = factory.and(parentExpression, expectedIn);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void addsAgentIdInQuery2() {
-        String agentId = UUID.randomUUID().toString();
-        String agentId2 = UUID.randomUUID().toString();
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        RolePrincipal agent2Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId2);
-        roles.add(agent1Role);
-        roles.add(agent2Role);
-        AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_AGENT_ID, null);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinarySetMembershipExpression);
-        Set<String> agentIdSet = new HashSet<>();
-        agentIdSet.add(agentId);
-        agentIdSet.add(agentId2);
-        Expression expected = new ExpressionFactory().in(Key.AGENT_ID, agentIdSet, String.class);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void returnsAllForUnrelatedQuery() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        // want for the agent id key to not be present in category
-        AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(TEST_DESC_NULL_AGENT_ID, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertNull(result.getFilterExpression());
-    }
-    
-    @Test
-    public void returnsParentExpressionForUnrelatedQuery() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        Expression parentExpression = new ExpressionFactory().equalTo(Key.AGENT_ID, "testKey");
-        AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles);
-        // want for the agent id key to not be present in category
-        FilterResult result = filter.applyFilter(TEST_DESC_NULL_AGENT_ID, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallbackTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
-
-import java.security.Principal;
-
-import org.junit.Test;
-
-import static org.mockito.Mockito.mock;
-
-public class DefaultPrincipalCallbackTest {
-
-    @Test
-    public void testCastSuccess() {
-        UserPrincipal principal = new UserPrincipal("foo");
-        DefaultPrincipalCallback callback = new DefaultPrincipalCallback();
-        UserPrincipal other = callback.getUserPrincipal(principal);
-        assertSame(principal, other);
-    }
-    
-    @Test
-    public void testCastFailure() {
-        Principal wrongPrincipal = mock(Principal.class);
-        DefaultPrincipalCallback callback = new DefaultPrincipalCallback();
-        try {
-            callback.getUserPrincipal(wrongPrincipal);
-            fail("should fail to cast!");
-        } catch (ClassCastException e) {
-            // pass
-        }
-    }
-    
-    
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/HostnameFilterTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.model.AgentInformation;
-import com.redhat.thermostat.storage.model.HostInfo;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinarySetMembershipExpression;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-public class HostnameFilterTest {
-
-    @Test
-    public void testReadAll() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal hostnameReadAll = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL);
-        roles.add(hostnameReadAll);
-        
-        HostnameFilter<?> filter = new HostnameFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertEquals(null, result.getFilterExpression());
-    }
-    
-    @Test
-    public void testReadAllAddsToParentExpression() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal hostnameReadAll = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL);
-        roles.add(hostnameReadAll);
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        HostnameFilter<?> filter = new HostnameFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-    
-    @Test
-    public void addsHostnameInQueryForHostInfo() {
-        String testHostname = "testhost.example.com";
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal hostnameRole = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + testHostname);
-        roles.add(hostnameRole);
-        
-        StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(HostInfoDAO.hostInfoCategory, "QUERY " + HostInfoDAO.hostInfoCategory.getName());
-        
-        Set<String> hostnames = new HashSet<>();
-        hostnames.add(testHostname);
-        Expression expected = new ExpressionFactory().in(HostInfoDAO.hostNameKey, hostnames, String.class);
-        HostnameFilter<HostInfo> filter = new HostnameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, null);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinarySetMembershipExpression);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void addsHostnameInQueryForHostInfoAndAddsParentExpression() {
-        String testHostname = "testhost.example.com";
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal hostnameRole = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + testHostname);
-        roles.add(hostnameRole);
-        
-        StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(HostInfoDAO.hostInfoCategory, "QUERY " + HostInfoDAO.hostInfoCategory.getName());
-        
-        Set<String> hostnames = new HashSet<>();
-        hostnames.add(testHostname);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        Expression expectedIn = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class);
-        Expression expected = factory.and(parentExpression, expectedIn);
-        HostnameFilter<HostInfo> filter = new HostnameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinaryLogicalExpression);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void byPassesFilterForUnrelatedQuery() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName());
-        
-        HostnameFilter<AgentInformation> filter = new HostnameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertNull(result.getFilterExpression());
-    }
-    
-    @Test
-    public void byPassesFilterForUnrelatedQueryAndParentExpression() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName());
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        HostnameFilter<AgentInformation> filter = new HostnameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallbackTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.security.Principal;
-import java.util.Set;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginContext;
-
-import org.eclipse.jetty.jaas.JAASUserPrincipal;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.web.server.containers.ContainerVersion;
-import com.redhat.thermostat.web.server.containers.ServletContainerInfo;
-
-public class JettyPrincipalCallbackTest {
-    
-    private ContainerVersion jetty9Version;
-    private ContainerVersion jetty8Version;
-    private ContainerVersion unknownVersion;
-
-    @Before
-    public void setup() {
-        jetty9Version = mock(ContainerVersion.class);
-        when(jetty9Version.getMajor()).thenReturn(9);
-        jetty8Version = mock(ContainerVersion.class);
-        when(jetty8Version.getMajor()).thenReturn(8);
-        unknownVersion = mock(ContainerVersion.class);
-        when(unknownVersion.getMajor()).thenReturn(100);
-    }
-    
-    @Test
-    public void canGetUserPrincipalJetty9() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getContainerVersion()).thenReturn(jetty9Version);
-        Subject subject = new Subject();
-        String principalName = "foo";
-        UserPrincipal userPrincipal = new UserPrincipal(principalName);
-        Set<Principal> principals = subject.getPrincipals();
-        principals.add(userPrincipal);
-        LoginContext loginContext = mock(LoginContext.class);
-        Principal principal = new JAASUserPrincipal(principalName, subject, loginContext);
-        
-        JettyPrincipalCallback callback = new JettyPrincipalCallback(info);
-        UserPrincipal other = callback.getUserPrincipal(principal);
-        assertSame(userPrincipal, other);
-    }
-    
-    @Test
-    public void canGetUserPrincipalJetty8() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getContainerVersion()).thenReturn(jetty8Version);
-        Subject subject = new Subject();
-        String principalName = "foo";
-        UserPrincipal userPrincipal = new UserPrincipal(principalName);
-        Set<Principal> principals = subject.getPrincipals();
-        principals.add(userPrincipal);
-        LoginContext loginContext = mock(LoginContext.class);
-        // use the jetty 8 principal
-        Principal principal = new org.eclipse.jetty.plus.jaas.JAASUserPrincipal(principalName, subject, loginContext);
-        
-        JettyPrincipalCallback callback = new JettyPrincipalCallback(info);
-        UserPrincipal other = callback.getUserPrincipal(principal);
-        assertSame(userPrincipal, other);
-    }
-    
-    @Test
-    public void failsOnUnknownPrincipal() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getContainerVersion()).thenReturn(unknownVersion);
-        Principal principal = mock(Principal.class);
-        JettyPrincipalCallback callback = new JettyPrincipalCallback(info);
-        try {
-            callback.getUserPrincipal(principal);
-            fail("should have failed to retrieve user principal from non-jetty principal");
-        } catch (IllegalStateException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void testNoUserPrincipalInSetOfPrincipals() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getContainerVersion()).thenReturn(jetty9Version);
-        Subject subject = new Subject();
-        String principalName = "foo";
-        LoginContext loginContext = mock(LoginContext.class);
-        Principal principal = new JAASUserPrincipal(principalName, subject, loginContext);
-        
-        JettyPrincipalCallback callback = new JettyPrincipalCallback(info);
-        try {
-            callback.getUserPrincipal(principal);
-            fail("should have thrown ISE, since no thermostat UserPrincipal is in the principal set");
-        } catch (IllegalStateException e) {
-            assertEquals("Number of thermostat user principals must be exactly 1!", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void testMoreThanOneUserPrincipalsInSetOfPrincipals() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getContainerVersion()).thenReturn(jetty9Version);
-        Subject subject = new Subject();
-        String principalName = "foo";
-        UserPrincipal userPrincipal = new UserPrincipal(principalName);
-        Set<Principal> principals = subject.getPrincipals();
-        UserPrincipal userPrincipal2 = new UserPrincipal("other");
-        principals.add(userPrincipal);
-        principals.add(userPrincipal2);
-        LoginContext loginContext = mock(LoginContext.class);
-        Principal principal = new JAASUserPrincipal(principalName, subject, loginContext);
-        
-        JettyPrincipalCallback callback = new JettyPrincipalCallback(info);
-        try {
-            callback.getUserPrincipal(principal);
-            fail("should have thrown ISE, since 2 thermostat UserPrincipals are in the principal set");
-        } catch (IllegalStateException e) {
-            assertEquals("Number of thermostat user principals must be exactly 1!", e.getMessage());
-        }
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactoryTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.redhat.thermostat.web.server.containers.ContainerName;
-import com.redhat.thermostat.web.server.containers.ServletContainerInfo;
-
-public class PrincipalCallbackFactoryTest {
-
-    @Test
-    public void unknownReturnsDefault() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getName()).thenReturn(ContainerName.UNKNOWN);
-        PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info);
-        PrincipalCallback cb = factory.getCallback();
-        assertNotNull(cb);
-        assertTrue(cb instanceof DefaultPrincipalCallback);
-    }
-    
-    @Test
-    public void tomcatReturnsDefault() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getName()).thenReturn(ContainerName.TOMCAT);
-        PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info);
-        PrincipalCallback cb = factory.getCallback();
-        assertNotNull(cb);
-        assertTrue(cb instanceof DefaultPrincipalCallback);
-    }
-    
-    @Test
-    public void jettyReturnsJettyCallBack() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getName()).thenReturn(ContainerName.JETTY);
-        PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info);
-        PrincipalCallback cb = factory.getCallback();
-        assertNotNull(cb);
-        assertTrue(cb instanceof JettyPrincipalCallback);
-    }
-    
-    @Test
-    public void wildflyReturnsDefault() {
-        ServletContainerInfo info = mock(ServletContainerInfo.class);
-        when(info.getName()).thenReturn(ContainerName.WILDFLY);
-        PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info);
-        PrincipalCallback cb = factory.getCallback();
-        assertNotNull(cb);
-        assertTrue(cb instanceof DefaultPrincipalCallback);
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/RolePrincipalTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-
-import org.junit.Test;
-
-public class RolePrincipalTest {
-    
-    @Test
-    public void testEmptyRoles() {
-        RolePrincipal principal = new RolePrincipal("RolesContainer");
-        assertEquals(false, principal.members().hasMoreElements());
-        assertEquals(false, principal.isMember(new RolePrincipal("not-there")));
-        assertEquals(false, principal.isMember(new UserPrincipal("user also not there")));
-        assertEquals("RolesContainer", principal.getName());
-    }
-    
-    @Test
-    public void canRemoveMembers() {
-        RolePrincipal principal = new RolePrincipal("Testing");
-        assertFalse(principal.removeMember(new RolePrincipal("other")));
-        assertFalse(principal.removeMember(new UserPrincipal("testuser")));
-        RolePrincipal firstRoleMember = new RolePrincipal("first");
-        RolePrincipal secondRoleMember = new RolePrincipal("second");
-        RolePrincipal thirdRoleMember = new RolePrincipal("third");
-        principal.addMember(firstRoleMember);
-        assertTrue("first member of Testing", principal.removeMember(firstRoleMember));
-        principal.addMember(secondRoleMember);
-        principal.addMember(thirdRoleMember);
-        assertTrue("third member of Testing", principal.removeMember(thirdRoleMember));
-        List<String> members = new ArrayList<>();
-        @SuppressWarnings("unchecked")
-        Enumeration<Principal> roles = (Enumeration<Principal>) principal.members();
-        while (roles.hasMoreElements()) {
-            members.add(roles.nextElement().getName());
-        }
-        assertEquals(1, members.size());
-        assertEquals("second", members.get(0));
-    }
-    
-    @Test
-    public void rolePrincipalDoesNotAllowNonGroupsToBeAdded() {
-        RolePrincipal role = new RolePrincipal("test");
-        try {
-            role.addMember(new UserPrincipal("something"));
-            fail("UserPrincipal not a Group, should not come here!");
-        } catch (IllegalArgumentException e) {
-            // pass
-        }
-    }
-    
-    @Test( expected = NullPointerException.class )
-    public void nullName() {
-        new RolePrincipal(null);
-    }
-    
-    @Test
-    public void isMemberWorksForNestedGroups() {
-        RolePrincipal principal = new RolePrincipal("Roles");
-        RolePrincipal otherRole = new RolePrincipal("Nested 1");
-        RolePrincipal thirdRole = new RolePrincipal("find-me");
-        RolePrincipal notExistingRole = new RolePrincipal("notthere");
-        otherRole.addMember(thirdRole);
-        principal.addMember(otherRole);
-        assertEquals("find-me member of Nested 1 which is member of Roles", true, principal.isMember(thirdRole));
-        assertEquals(false, principal.isMember(notExistingRole));
-        assertTrue(otherRole.removeMember(thirdRole));
-        assertEquals("find-me no longer member of Nested 1 (which is still a member of Roles)", false, principal.isMember(thirdRole));
-    }
-    
-    @Test
-    public void testEquals() {
-        UserPrincipal user = new UserPrincipal("test");
-        RolePrincipal role = new RolePrincipal("test");
-        assertFalse("Roles and users must not be equal", role.equals(user));
-        assertTrue(role.equals(role));
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,342 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import java.security.Principal;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.dao.HostInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.HostInfo;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-public class UserPrincipalTest {
-    
-    private static class FooPojo implements Pojo {
-        // empty dummy pojo.
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void testConstructor() {
-        new UserPrincipal(null);
-    }
-    
-    @Test
-    public void getName() {
-        UserPrincipal p = new UserPrincipal("testing");
-        assertEquals("testing", p.getName());
-    }
-    
-    @Test
-    public void canSetRoles() {
-        UserPrincipal p = new UserPrincipal("superuser");
-        try {
-            p.setRoles(null);
-            fail("null roles not allowed");
-        } catch (NullPointerException e) {
-            // pass
-        }
-        Set<BasicRole> roles = new HashSet<>();
-        BasicRole role = mock(BasicRole.class);
-        roles.add(role);
-        p.setRoles(roles);
-        assertEquals(1, p.getRoles().size());
-    }
-
-    @Test
-    public void setRolesDefensiveCopy() {
-        UserPrincipal p = new UserPrincipal("testuser");
-        Set<BasicRole> roles = new HashSet<>();
-        BasicRole fooRole = mock(BasicRole.class);
-        roles.add(fooRole);
-        p.setRoles(roles);
-        BasicRole barRole = mock(BasicRole.class);
-        roles.add(barRole);
-        assertFalse(p.getRoles().contains(barRole));
-    }
-
-    @Test
-    public void getRolesDoesntLeak() {
-        UserPrincipal p = new UserPrincipal("testuser");
-        Set<BasicRole> roles = p.getRoles();
-        BasicRole fooRole = mock(BasicRole.class);
-        roles.add(fooRole);
-        assertFalse(p.getRoles().contains(fooRole));
-    }
-    
-    @Test
-    public void testEquals() {
-        UserPrincipal p = new UserPrincipal("testuser");
-        assertTrue(p.equals(p));
-        SimplePrincipal p2 = new SimplePrincipal("testuser");
-        assertTrue(p2.equals(p));
-        assertTrue(p.equals(p2));
-        SimplePrincipal p3 = new SimplePrincipal("Tester");
-        assertFalse(p2.equals(p3));
-        assertFalse(p.equals(p3));
-        Principal principal = new Principal() {
-
-            @Override
-            public String getName() {
-                return "testuser";
-            }
-            
-        };
-        assertTrue(p.equals(principal));
-    }
-    
-    @Test
-    public void readAllRoleBypassesReadFilters() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal readEverything = new RolePrincipal(Roles.GRANT_READ_ALL);
-        roles.add(readEverything);
-        SimplePrincipal testMe = new SimplePrincipal("test me");
-        testMe.setRoles(roles);
-        FilterResult result = testMe.getReadFilter(null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertNull(result.getFilterExpression());
-    }
-    
-    @Test
-    public void testEntireFilterChainNoSpecificAgentIdVmId() {
-        String agentId = "someAgentID";
-        String vmId = "someVmID";
-        String vmUsername = "someUser";
-        RolePrincipal readAllHosts = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL);
-        RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        RolePrincipal readVmUsername = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + vmUsername);
-        
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(readAllHosts);
-        roles.add(readAgentId);
-        roles.add(readVmUsername);
-        roles.add(readVmId);
-        
-        assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL));
-        assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL));
-        assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL));
-        assertFalse(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL));
-        SimplePrincipal testMe = new SimplePrincipal("test me");
-        testMe.setRoles(roles);
-        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName());
-        
-        // should pass through agentId -> hostname -> vmId -> vmUsername filters
-        FilterResult result = testMe.getReadFilter(desc);
-        
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        ExpressionFactory factory = new ExpressionFactory();
-        Set<String> agentIds = new HashSet<>();
-        agentIds.add(agentId);
-        Set<String> vmIds = new HashSet<>();
-        vmIds.add(vmId);
-        Expression agentInExpr = factory.in(Key.AGENT_ID, agentIds, String.class);
-        Expression vmIdInExpr = factory.in(Key.VM_ID, vmIds, String.class);
-        Set<String> vmUsernames = new HashSet<>();
-        vmUsernames.add(vmUsername);
-        Expression vmIdUsernameInExpr = factory.in(VmInfoDAO.usernameKey, vmUsernames, String.class);
-        Expression expected = factory.and(factory.and(agentInExpr, vmIdInExpr), vmIdUsernameInExpr);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void testEntireFilterChainSpecificAgentIdVmId() {
-        String agentId = "someAgentID";
-        String vmId = "someVmID";
-        RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(HostnameFilter.GRANT_HOSTS_READ_ALL);
-        roles.add(readAgentId);
-        roles.add(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL);
-        roles.add(readVmId);
-        
-        assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL));
-        assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL));
-        assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL));
-        assertTrue(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL));
-        SimplePrincipal testMe = new SimplePrincipal("test me");
-        testMe.setRoles(roles);
-        
-        // want for the agent/vm id key to be present in category
-        Key<?>[] keys = new Key[] {
-             Key.AGENT_ID, Key.VM_ID
-        };
-        Category<FooPojo> agentAndVmIdCat = new Category<>("agentAndVmIdCat", FooPojo.class, keys);
-        StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(agentAndVmIdCat, "QUERY agentAndVmIdCat");
-        
-        // should pass through agentId -> hostname -> vmId -> vmUsername filters
-        FilterResult result = testMe.getReadFilter(desc);
-        
-        // should return all, since ACL allows specific agentId/vmIds
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        Expression expected = getExpectedAgentIdVmIdExpression(agentId, vmId);
-        assertEquals(expected, result.getFilterExpression());
-    }
-    
-    private Expression getExpectedAgentIdVmIdExpression(String agentId,
-            String vmId) {
-        ExpressionFactory factory = new ExpressionFactory();
-        Set<String> agentIdSet = new HashSet<>();
-        agentIdSet.add(agentId);
-        Expression agentIdExp = factory.in(Key.AGENT_ID, agentIdSet, String.class);
-        Set<String> vmIdSet = new HashSet<>();
-        vmIdSet.add(vmId);
-        Expression vmIdExp = factory.in(Key.VM_ID, vmIdSet, String.class);
-        return factory.and(agentIdExp, vmIdExp);
-    }
-
-    @Test
-    public void testEntireFilterChainSpecificAgentIdVmIdPlusHostname() {
-        String agentId = "someAgentID";
-        String vmId = "someVmID";
-        String hostname = "somehost.example.com";
-        RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        RolePrincipal readHostname = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + hostname);
-        
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(readHostname);
-        roles.add(readAgentId);
-        roles.add(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL);
-        roles.add(readVmId);
-        
-        assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL));
-        assertFalse(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL));
-        assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL));
-        assertTrue(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL));
-        SimplePrincipal testMe = new SimplePrincipal("test me");
-        testMe.setRoles(roles);
-        StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(HostInfoDAO.hostInfoCategory, "QUERY " + HostInfoDAO.hostInfoCategory.getName());
-        
-        // should pass through agentId -> hostname -> vmId -> vmUsername filters
-        FilterResult result = testMe.getReadFilter(desc);
-        
-        // should return query expression in order to allow only specific
-        // hostname and specific agent id. Since the category does not
-        // include vmId, nothing is added by the vm id filter.
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        ExpressionFactory factory = new ExpressionFactory();
-        Set<String> agentIdSet = new HashSet<>();
-        agentIdSet.add(agentId);
-        Expression agentIdExp = factory.in(Key.AGENT_ID, agentIdSet, String.class);
-        Set<String> hostnames = new HashSet<>();
-        hostnames.add(hostname);
-        Expression hostnameExp = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class);
-        Expression expected = factory.and(agentIdExp, hostnameExp);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void testEntireFilterChainSpecificAgentIdVmIdPlusVmUsername() {
-        String agentId = "someAgentID";
-        String vmId = "someVmID";
-        String vmUserame = "someOwningUser";
-        RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId);
-        RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        RolePrincipal readVmUsername = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + vmUserame);
-        
-        Set<BasicRole> roles = new HashSet<>();
-        roles.add(readVmUsername);
-        roles.add(readAgentId);
-        roles.add(HostnameFilter.GRANT_HOSTS_READ_ALL);
-        roles.add(readVmId);
-        
-        assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL));
-        assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL));
-        assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL));
-        assertFalse(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL));
-        SimplePrincipal testMe = new SimplePrincipal("test me");
-        testMe.setRoles(roles);
-        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName());
-        
-        // should pass through agentId -> hostname -> vmId -> vmUsername filters
-        FilterResult result = testMe.getReadFilter(desc);
-        
-        // should return query expression in order to allow only specific
-        // owning vm username.
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        ExpressionFactory factory = new ExpressionFactory();
-        Set<String> usernames = new HashSet<>();
-        usernames.add(vmUserame);
-        Expression userNameExp = factory.in(VmInfoDAO.usernameKey, usernames, String.class);
-        Set<String> agentIdSet = new HashSet<>();
-        agentIdSet.add(agentId);
-        Expression agentIdExp = factory.in(Key.AGENT_ID, agentIdSet, String.class);
-        Set<String> vmIdSet = new HashSet<>();
-        vmIdSet.add(vmId);
-        Expression vmIdExp = factory.in(Key.VM_ID, vmIdSet, String.class);
-        Expression lhs = factory.and(agentIdExp, vmIdExp);
-        Expression expected = factory.and(lhs, userNameExp);
-        assertEquals(expected, actual);
-    }
-    
-    
-    @SuppressWarnings("serial")
-    private static class SimplePrincipal extends UserPrincipal {
-        
-        public SimplePrincipal(String name) {
-            super(name);
-        }
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmIdFilterTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.model.Pojo;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinarySetMembershipExpression;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-public class VmIdFilterTest {
-    
-    private static class FooPojo implements Pojo {
-        // Dummy class for testing
-    }
-    
-    private static final Category<FooPojo> TEST_NON_NULL_CATEGORY = new Category<>("foo-vmid-filter-test", FooPojo.class, Key.VM_ID);
-    private static final Category<FooPojo> TEST_NULL_CATEGORY = new Category<>("foo-vmid-filter-test-null", FooPojo.class);
-    /**
-     * A query descriptor which will return a non-null Key for the "vmId" name.
-     */
-    private static final StatementDescriptor<FooPojo> TEST_DESC_NON_NULL_VM_ID = new StatementDescriptor<>(TEST_NON_NULL_CATEGORY, "QUERY foo");
-    /**
-     * A query descriptor which will return a null Key for the "vmId" name.
-     */
-    private static final StatementDescriptor<FooPojo> TEST_DESC_NULL_VM_ID = new StatementDescriptor<>(TEST_NULL_CATEGORY, "QUERY foo-null");
-
-    @Test
-    public void testReadAll() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmIdReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL);
-        roles.add(vmIdReadAll);
-        
-        VmIdFilter<?> filter = new VmIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertEquals(null, result.getFilterExpression());
-    }
-    
-    @Test
-    public void testReadAllAndParentExpression() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmIdReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL);
-        roles.add(vmIdReadAll);
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        VmIdFilter<?> filter = new VmIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-    
-    @Test
-    public void addsVmIdInQuery() {
-        String vmId = UUID.randomUUID().toString();
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        roles.add(vmIdRole);
-        VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_VM_ID, null);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinarySetMembershipExpression);
-        Set<String> vmIdSet = new HashSet<>();
-        vmIdSet.add(vmId);
-        Expression expected = new ExpressionFactory().in(Key.VM_ID, vmIdSet, String.class);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void addsVmIdInQueryAndParentExpression() {
-        String vmId = UUID.randomUUID().toString();
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        roles.add(vmIdRole);
-        VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_VM_ID, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinaryLogicalExpression);
-        Set<String> vmIdSet = new HashSet<>();
-        vmIdSet.add(vmId);
-        
-        Expression expectedIn = factory.in(Key.VM_ID, vmIdSet, String.class);
-        Expression expected = factory.and(parentExpression, expectedIn);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void addsVmIdInQuery2() {
-        String vmId = UUID.randomUUID().toString();
-        String vmId2 = UUID.randomUUID().toString();
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vm1Role = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId);
-        RolePrincipal vm2Role = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId2);
-        roles.add(vm1Role);
-        roles.add(vm2Role);
-        VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles);
-        FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_VM_ID, null);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinarySetMembershipExpression);
-        Set<String> vmIdSet = new HashSet<>();
-        vmIdSet.add(vmId);
-        vmIdSet.add(vmId2);
-        Expression expected = new ExpressionFactory().in(Key.VM_ID, vmIdSet, String.class);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void returnsAllForUnrelatedQuery() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles);
-        // want to have a null retval of vmId
-        FilterResult result = filter.applyFilter(TEST_DESC_NULL_VM_ID, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertNull(result.getFilterExpression());
-    }
-    
-    @Test
-    public void returnsParentExpressionForUnrelatedQuery() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles);
-        // want to have a null retval of vmId
-        FilterResult result = filter.applyFilter(TEST_DESC_NULL_VM_ID, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmUsernameFilterTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.AgentInformation;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.storage.query.BinaryLogicalExpression;
-import com.redhat.thermostat.storage.query.BinarySetMembershipExpression;
-import com.redhat.thermostat.storage.query.Expression;
-import com.redhat.thermostat.storage.query.ExpressionFactory;
-import com.redhat.thermostat.web.server.auth.FilterResult.ResultType;
-
-public class VmUsernameFilterTest {
-    
-    @Test
-    public void testReadAll() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmUsernameReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL);
-        roles.add(vmUsernameReadAll);
-        
-        VmUsernameFilter<?> filter = new VmUsernameFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertEquals(null, result.getFilterExpression());
-    }
-    
-    @Test
-    public void testReadAllWithParentExpression() {
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmUsernameReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL);
-        roles.add(vmUsernameReadAll);
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        VmUsernameFilter<?> filter = new VmUsernameFilter<>(roles);
-        FilterResult result = filter.applyFilter(null, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-    
-    @Test
-    public void addsVmUsernameInQueryForVmInfo() {
-        String testUsername = "fooBar";
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmUsernameRole = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + testUsername);
-        roles.add(vmUsernameRole);
-        
-        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName());
-        
-        Set<String> usernames = new HashSet<>();
-        usernames.add(testUsername);
-        Expression expected = new ExpressionFactory().in(VmInfoDAO.usernameKey, usernames, String.class);
-        VmUsernameFilter<VmInfo> filter = new VmUsernameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, null);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinarySetMembershipExpression);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void addsVmUsernameInQueryForVmInfoAndParentExpression() {
-        String testUsername = "fooBar";
-        Set<BasicRole> roles = new HashSet<>();
-        RolePrincipal vmUsernameRole = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + testUsername);
-        roles.add(vmUsernameRole);
-        
-        StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName());
-        
-        Set<String> usernames = new HashSet<>();
-        usernames.add(testUsername);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        Expression expectedIn = factory.in(VmInfoDAO.usernameKey, usernames, String.class);
-        Expression expected = factory.and(parentExpression, expectedIn);
-        VmUsernameFilter<VmInfo> filter = new VmUsernameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        Expression actual = result.getFilterExpression();
-        assertTrue(actual instanceof BinaryLogicalExpression);
-        assertEquals(expected, actual);
-    }
-    
-    @Test
-    public void byPassesFilterForUnrelatedQuery() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName());
-        
-        VmUsernameFilter<AgentInformation> filter = new VmUsernameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, null);
-        assertEquals(ResultType.ALL, result.getType());
-        assertNull(result.getFilterExpression());
-    }
-    
-    @Test
-    public void byPassesFilterForUnrelatedQueryAndParentExpression() {
-        Set<BasicRole> roles = new HashSet<>();
-        
-        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName());
-        
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey");
-        VmUsernameFilter<AgentInformation> filter = new VmUsernameFilter<>(roles);
-        FilterResult result = filter.applyFilter(desc, parentExpression);
-        assertEquals(ResultType.QUERY_EXPRESSION, result.getType());
-        assertNotNull(result.getFilterExpression());
-        assertEquals(parentExpression, result.getFilterExpression());
-    }
-    
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipalTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Enumeration;
-import java.util.Vector;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class WrappedRolePrincipalTest {
-
-    private Group group;
-    @SuppressWarnings("rawtypes")
-    private Enumeration members = new Vector().elements();
-    
-    @SuppressWarnings("unchecked")
-    @Before
-    public void setup() {
-        group = mock(Group.class);
-        when(group.addMember(any(Principal.class))).thenReturn(true);
-        when(group.isMember(any(Principal.class))).thenReturn(true);
-        when(group.getName()).thenReturn("group-under-the-hood");
-        when(group.members()).thenReturn(members);
-        when(group.removeMember(any(Principal.class))).thenReturn(false);
-    }
-    
-    @After
-    public void tearDown() {
-        group = null;
-    }
-    
-    @Test
-    public void testAllDelegates() {
-        WrappedRolePrincipal p = new WrappedRolePrincipal(group);
-        Principal mock = mock(Principal.class);
-        assertEquals(true, p.addMember(mock));
-        assertEquals(true, p.isMember(mock));
-        assertEquals("group-under-the-hood", p.getName());
-        assertEquals(members, p.members());
-        assertEquals(false, p.removeMember(mock));
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModuleTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Map;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-
-import org.junit.Test;
-
-public class AbstractLoginModuleTest {
-
-    @Test
-    public void canGetUserNameFromCallBack() throws LoginException {
-        SimpleCallBackHandler handler = new SimpleCallBackHandler("testuser");
-        LoginModuleImpl loginModule = new LoginModuleImpl();
-        loginModule.initialize(new Subject(), handler, null, null);
-        assertEquals("testuser", loginModule.getUsernameFromCallBack());
-    }
-    
-    @Test
-    public void canGetUserPasswordFromCallBack() throws LoginException {
-        SimpleCallBackHandler handler = new SimpleCallBackHandler("testuser", "testpassword".toCharArray());
-        LoginModuleImpl loginModule = new LoginModuleImpl();
-        loginModule.initialize(new Subject(), handler, null, null);
-        Object[] creds = loginModule.getUsernamePasswordFromCallBack();
-        String user = (String)creds[0];
-        char[] pwd = (char[])creds[1];
-        assertEquals("testuser", user);
-        assertEquals("testpassword", new String(pwd));
-    }
-    
-    private static class LoginModuleImpl extends AbstractLoginModule {
-
-        @Override
-        public void initialize(Subject subject,
-                CallbackHandler callbackHandler, Map<String, ?> sharedState,
-                Map<String, ?> options) {
-            this.callBackHandler = callbackHandler;
-        }
-
-        @Override
-        public boolean login() throws LoginException {
-            // don't care
-            return false;
-        }
-
-        @Override
-        public boolean commit() throws LoginException {
-            // don't care
-            return false;
-        }
-
-        @Override
-        public boolean abort() throws LoginException {
-            // don't care
-            return false;
-        }
-
-        @Override
-        public boolean logout() throws LoginException {
-            // don't care
-            return false;
-        }
-        
-        @Override
-        public String getUsernameFromCallBack() throws LoginException {
-            return super.getUsernameFromCallBack();
-        }
-        
-        @Override
-        public Object[] getUsernamePasswordFromCallBack() throws LoginException {
-            return super.getUsernamePasswordFromCallBack();
-        }
-        
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModuleTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.security.Principal;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
-import javax.security.auth.login.Configuration;
-import javax.security.auth.login.LoginException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.web.server.auth.BasicRole;
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-import com.redhat.thermostat.web.server.auth.UserPrincipal;
-
-public class DelegateLoginModuleTest {
-
-    private Subject subject;
-    private Map<String, Object> mockSharedState;
-    private Map<String, Object> mockOptions;
-    private CallbackHandler mockCallBack;
-    
-    @Before
-    public void setup() {
-        subject = new Subject();
-        mockSharedState = new HashMap<>();
-        mockOptions = new HashMap<>();
-        // DelegateLoginModule uses the name callback
-        mockCallBack = new SimpleCallBackHandler("testUser", "doesn't matter".toCharArray());
-        // sets jaas config so as to use Stub*DelegateLoginModule
-        Configuration config = new TestConfiguration();
-        Configuration.setConfiguration(config);
-    }
-    
-    @After
-    public void teardown() {
-        subject = null;
-        mockSharedState = null;
-        mockOptions = null;
-        mockCallBack = null;
-    }
-    
-    @Test
-    public void testBasicsSuccess() throws Exception {
-        DelegateLoginModule delegateLogin = new DelegateLoginModule("Success");
-        delegateLogin.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue("Stub delegate in use is always successfull", delegateLogin.login());
-        assertTrue("Stub delegate in use is always successfull", delegateLogin.commit());
-        // SubSuccessDelegateLoginModule added one user principal
-        // 'testUser' and one role principal 'testRole'.
-        Subject subject = delegateLogin.getSubject();
-        assertEquals(this.subject, subject);
-        Set<Principal> principals = subject.getPrincipals();
-        assertEquals(2, principals.size());
-        for (Principal p : principals) {
-            if (p.getName().equals("testUser")) {
-                // user principal
-                assertTrue(p instanceof UserPrincipal);
-                UserPrincipal uPrincipal = (UserPrincipal) p;
-                assertNotNull("Should now be a thermostat UserPrincipal containing roles", uPrincipal.getRoles());
-                assertEquals(1, uPrincipal.getRoles().size());
-                for (BasicRole role : uPrincipal.getRoles()) {
-                    assertEquals("testRole", role.getName());
-                }
-            }
-            if (p.getName().equals("testRole")) {
-                assertTrue("Should have been wrapped into a BasicRole", p instanceof BasicRole);
-            }
-        }
-        // Test the same another way for good measure.
-        assertTrue(principals.contains(new UserPrincipal("testUser")));
-        assertTrue(principals.contains(new RolePrincipal("testRole")));
-        
-        // now logout. we expect principals to be cleared
-        delegateLogin.logout();
-        assertEquals(0, subject.getPrincipals().size());
-    }
-    
-    @Test
-    public void testBasicsFailure() throws Exception {
-        DelegateLoginModule delegateLogin = new DelegateLoginModule("Failure");
-        delegateLogin.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        // add some principal to the subject in order to make sure delegate
-        // clears principals on login failure.
-        Principal mock = new Principal() {
-
-            @Override
-            public String getName() {
-                return "tester";
-            }
-            
-        };
-        subject.getPrincipals().add(mock);
-        assertEquals(1, subject.getPrincipals().size());
-        try {
-            // this triggers abort() being called for the delegate.
-            delegateLogin.login();
-            fail("StubFailureDelegateLoginModule should have thrown LE");
-        } catch (LoginException e) {
-            // pass
-        }
-        assertEquals(0, subject.getPrincipals().size());
-    }
-    
-    @Test
-    public void testAbort() throws LoginException {
-        // add some principal to the subject in order to make sure delegate
-        // clears principals on login failure.
-        Principal mock = new Principal() {
-
-            @Override
-            public String getName() {
-                return "tester";
-            }
-            
-        };
-        subject.getPrincipals().add(mock);
-        assertEquals(1, subject.getPrincipals().size());
-        DelegateLoginModule delegateLogin = new DelegateLoginModule("Failure");
-        delegateLogin.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        // simulate abort which should clear any principals from the subject
-        delegateLogin.abort();
-        assertEquals(0, subject.getPrincipals().size());
-    }
-    
-    private class TestConfiguration extends Configuration {
-        
-        private final AppConfigurationEntry successEntry =
-                new AppConfigurationEntry(StubSuccessDelegateLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>());
-        private final AppConfigurationEntry failureEntry =
-                new AppConfigurationEntry(StubFailureDelegateLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>());
-        
-        @Override
-        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-            AppConfigurationEntry entry = null;
-            if (name.equals("Failure")) {
-                entry = failureEntry;
-            } else if (name.equals("Success")) {
-                entry = successEntry;
-            } else {
-                throw new RuntimeException("Don't know how to handle config name '" + name + "'");
-            }
-            return new AppConfigurationEntry[] { entry };
-        }
-        
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidatorTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.junit.After;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-
-public class PropertiesUserValidatorTest {
-    
-    private PropertiesUserValidator validator;
-
-    @Before
-    public void setup() {
-        String testFile = decodeFilePath(this.getClass().getResource("/test_users.properties"));
-        validator = new PropertiesUserValidator(testFile);   
-    }
-    
-    @After
-    public void tearDown() {
-        validator = null;
-    }
-    
-    
-    @Test
-    public void authenticationFailsForNonExistingUser() {
-        try {
-            validator.authenticate("does not exist", null);
-            fail("user does not exist in file");
-        } catch (UserValidationException e) {
-            // pass
-            assertEquals("User 'does not exist' not found", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void passwordMatch() {
-        try {
-            validator.authenticate("user1", "passwd1".toCharArray());
-            validator.authenticate("strange\nuser", "testMe".toCharArray());
-            validator.authenticate("c102892{0}", "test".toCharArray());
-            // extra spaces are remved from properties system
-            validator.authenticate("multiuser", "blah\ntest test".toCharArray());
-            // '\0' in test_users.properties become '0'
-            validator.authenticate("strange0user", "test0Me".toCharArray());
-            // pass
-        } catch (UserValidationException e) {
-            e.printStackTrace();
-            fail("should have been able to authenticate user");
-        }
-    }
-    
-    @Test
-    public void passwordMismatch() {
-        try {
-            validator.authenticate("user1", "passwD1".toCharArray());
-            fail("password does not match!");
-        } catch (UserValidationException e) {
-            assertEquals("Login failed!", e.getMessage());
-        }
-        try {
-            validator.authenticate("c102892{0}", "passwd1".toCharArray());
-        } catch (UserValidationException e) {
-            assertEquals("Login failed!", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void testInit() {
-        Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null);
-        try {
-            new PropertiesUserValidator();
-            fail("THERMOSTAT_HOME not set, should have failed!");
-        } catch (InvalidConfigurationException e) {
-            // pass
-            assertTrue(e.getMessage().contains("THERMOSTAT_HOME"));
-        }
-    }
-    
-    @Test
-    public void testInitWithMissingFile() {
-        try {
-            new PropertiesUserValidator("file/which/does/not/exist");
-        } catch (InvalidConfigurationException e) {
-            // pass
-            assertEquals("Unable to load user database", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void canGetUserSet() {
-        Set<String> expectedSet = new HashSet<>(10);
-        expectedSet.add("user1");
-        expectedSet.add("testing");
-        expectedSet.add("multiuser");
-        expectedSet.add("c102892{0}");
-        expectedSet.add("strange\nuser");
-        expectedSet.add("strange0user");
-        Set<Object> actual = validator.getAllKnownUsers();
-        assertTrue(expectedSet.equals(actual));
-        expectedSet.remove("user1");
-        assertFalse(expectedSet.equals(actual));
-    }
-
-    private static String decodeFilePath(URL url) {
-        try {
-            // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so
-            // as to handle cases like that.
-            return URLDecoder.decode(url.getFile(), "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new AssertionError("UTF-8 not supported, huh?");
-        }
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModuleTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,331 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.security.Principal;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-import com.redhat.thermostat.web.server.auth.UserPrincipal;
-
-public class PropertiesUsernameRolesLoginModuleTest {
-    
-    private Subject subject;
-    private Map<String, Object> mockSharedState;
-    private Map<String, Object> mockOptions;
-    private CallbackHandler mockCallBack;
-    
-    @Before
-    public void setup() {
-        subject = new Subject();
-        mockSharedState = new HashMap<>();
-        mockOptions = new HashMap<>();
-    }
-    
-    @After
-    public void teardown() {
-        subject = null;
-        mockSharedState = null;
-        mockOptions = null;
-        mockCallBack = null;
-    }
-
-    @Test
-    public void canInitialize() {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("testUser", "testpassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        try {
-            // this must not throw an exception
-            loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-            // pass
-        } catch (Exception e) {
-            fail("Did not expect any exception here!");
-        }
-    }
-    
-    @Test
-    public void failsToLoginWithInvalidCredentials() {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        // testUser/testpassword not defined
-        mockCallBack = new SimpleCallBackHandler("testUser", "testpassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        try {
-            loginModule.login();
-            fail("testUser not defined in properties_module_test_users.properties");
-        } catch (LoginException e) {
-            // pass
-            assertEquals("User 'testUser' not found", e.getMessage());
-        }
-        mockCallBack = new SimpleCallBackHandler("user1", "wrongpassword".toCharArray());
-        loginModule = new PropertiesUsernameRolesLoginModule();
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        try {
-            loginModule.login();
-            fail("user1 provided wrong password!");
-        } catch (LoginException e) {
-            assertEquals("Login failed!", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void canLoginWithValidCredentials() {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        try {
-            boolean retval = loginModule.login();
-            // pass
-            assertTrue("Login should have returned true", retval);
-        } catch (LoginException e) {
-            fail("'user1' should be able to login");
-        }
-        mockCallBack = new SimpleCallBackHandler("user2", "password".toCharArray());
-        loginModule = new PropertiesUsernameRolesLoginModule();
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        try {
-            boolean retval = loginModule.login();
-            // pass
-            assertTrue("Login should have returned true", retval);
-        } catch (LoginException e) {
-            fail("'user2' should be able to login");
-        }
-    }
-    
-    @Test
-    public void canCommitOnSuccessfulLogin() throws LoginException {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue(loginModule.login());
-        try {
-            boolean retval = loginModule.commit();
-            // pass
-            assertTrue("Commit should have returned true", retval);
-        } catch (LoginException e) {
-            fail("'user1' should have been able to commit");
-        }
-        // assert principals are added to subject
-        Set<Principal> principals = subject.getPrincipals();
-        // my-role, my-role2, Roles, user1
-        assertEquals(4, principals.size());
-        assertTrue(principals.contains(new RolePrincipal("my-role")));
-        assertTrue(principals.contains(new RolePrincipal("my-role2")));
-        assertTrue(principals.contains(new RolePrincipal("Roles")));
-        assertTrue(principals.contains(new UserPrincipal("user1")));
-    }
-    
-    @Test
-    public void testRecursiveRoles() throws LoginException {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user2", "password".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue(loginModule.login());
-        try {
-            boolean retval = loginModule.commit();
-            // pass
-            assertTrue("Commit should have returned true", retval);
-        } catch (LoginException e) {
-            fail("'user2' should have been able to commit");
-        }
-        // assert principals are added to subject
-        Set<Principal> principals = subject.getPrincipals();
-        // new-role, role1, other-role, Roles, user2
-        assertEquals(5, principals.size());
-        assertTrue(principals.contains(new RolePrincipal("new-role")));
-        assertTrue(principals.contains(new RolePrincipal("role1")));
-        assertTrue(principals.contains(new RolePrincipal("Roles")));
-        // via recursive role 'role1'
-        assertTrue(principals.contains(new RolePrincipal("other-role")));
-        assertTrue(principals.contains(new UserPrincipal("user2")));
-    }
-    
-    @Test
-    public void testRecursiveRolesMultiple() throws LoginException {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user3", "password".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue(loginModule.login());
-        try {
-            boolean retval = loginModule.commit();
-            // pass
-            assertTrue("Commit should have returned true", retval);
-        } catch (LoginException e) {
-            fail("'user3' should have been able to commit");
-        }
-        // assert principals are added to subject
-        Set<Principal> principals = subject.getPrincipals();
-        // other-role, role1, Roles, user3
-        assertEquals(4, principals.size());
-        assertTrue(principals.contains(new RolePrincipal("role1")));
-        assertTrue(principals.contains(new RolePrincipal("Roles")));
-        // via recursive role 'role1'
-        assertTrue(principals.contains(new RolePrincipal("other-role")));
-        assertTrue(principals.contains(new UserPrincipal("user3")));
-        loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user2", "password".toCharArray());
-        subject = new Subject();
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue(loginModule.login());
-        try {
-            boolean retval = loginModule.commit();
-            // pass
-            assertTrue("Commit should have returned true", retval);
-        } catch (LoginException e) {
-            fail("'user2' should have been able to commit");
-        }
-        // assert principals are added to subject
-        principals = subject.getPrincipals();
-        // new-role, other-role, role1, Roles, user2
-        assertEquals(5, principals.size());
-        assertTrue(principals.contains(new RolePrincipal("role1")));
-        assertTrue(principals.contains(new RolePrincipal("Roles")));
-        // via recursive role 'role1'
-        assertTrue(principals.contains(new RolePrincipal("other-role")));
-        assertTrue(principals.contains(new UserPrincipal("user2")));
-        assertTrue(principals.contains(new RolePrincipal("new-role")));
-    }
-    
-    @Test
-    public void cannotCommitWithoutLoggingIn() throws LoginException {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        assertFalse(loginModule.commit());
-        
-        loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertFalse(loginModule.commit());
-        assertEquals(0, subject.getPrincipals().size());
-    }
-    
-    @Test
-    public void testLoginCommitAbort() throws LoginException {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue(loginModule.login());
-        assertTrue(loginModule.commit());
-        // assert principals are added to subject after login
-        Set<Principal> principals = subject.getPrincipals();
-        // my-role, my-role2, Roles, user1
-        assertEquals(4, principals.size());
-        assertTrue(loginModule.abort());
-        // make sure principals are cleared
-        assertEquals(0, principals.size());
-    }
-    
-    @Test
-    public void testLoginCommitLogout() throws LoginException {
-        LoginModule loginModule = new PropertiesUsernameRolesLoginModule();
-        mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray());
-        String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties"));
-        String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties"));
-        mockOptions.put("users.properties", userFile);
-        mockOptions.put("roles.properties", rolesFile);
-        loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions);
-        assertTrue(loginModule.login());
-        assertTrue(loginModule.commit());
-        // assert principals are added to subject after login
-        Set<Principal> principals = subject.getPrincipals();
-        // my-role, my-role2, Roles, user1
-        assertEquals(4, principals.size());
-        assertTrue(loginModule.logout());
-        // make sure principals are cleared
-        assertEquals(0, principals.size());
-    }
-
-    private static String decodeFilePath(URL url) {
-        try {
-            // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so
-            // as to handle cases like that.
-            return URLDecoder.decode(url.getFile(), "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new AssertionError("UTF-8 not supported, huh?");
-        }
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/RolesAmenderTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,281 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.security.Principal;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.junit.After;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.shared.config.InvalidConfigurationException;
-import com.redhat.thermostat.web.server.auth.BasicRole;
-import com.redhat.thermostat.web.server.auth.RolePrincipal;
-import com.redhat.thermostat.web.server.auth.spi.RolesAmender.RolesInfo;
-
-public class RolesAmenderTest {
-
-    private RolesAmender rolesAmender;
-    private String validFile;
-    private Set<Object> validUsers;
-    
-    @Before
-    public void setup() {
-        String testFile = decodeFilePath(this.getClass().getResource("/test_roles.properties"));
-        validFile = testFile;
-        Set<Object> users = new HashSet<>();
-        users.add("user1");
-        users.add("user2");
-        users.add("someuser");
-        users.add("someotheruser");
-        validUsers = Collections.unmodifiableSet(users);
-    }
-    
-    @After
-    public void tearDown() {
-        rolesAmender = null;
-        validFile = null;
-    }
-
-    @Test
-    public void testGetRolesDoesntLeak() {
-        rolesAmender = new RolesAmender(validFile, validUsers);
-        Set<BasicRole> roles = rolesAmender.getRoles("foo");
-        assertEquals(roles, Collections.emptySet());
-        BasicRole fooRole = mock(BasicRole.class);
-        roles.add(fooRole);
-        assertEquals(rolesAmender.getRoles("foo"), Collections.emptySet());
-    }
-
-    @Test
-    public void canParseRoles() {
-        rolesAmender = new RolesAmender(validFile, validUsers);
-        Set<BasicRole> roles = rolesAmender.getRoles("user1");
-        assertEquals(2, roles.size());
-        Map<String, Boolean> userRolesMap = new HashMap<>();
-        for (BasicRole role : roles) {
-            // don't expect role nesting
-            assertTrue(role instanceof RolePrincipal);
-            assertFalse(role.members().hasMoreElements());
-            userRolesMap.put(role.getName(), true);
-        }
-        assertTrue(userRolesMap.containsKey("my-role"));
-        assertTrue(userRolesMap.containsKey("my-role2"));
-        roles = rolesAmender.getRoles("user2");
-        // new-role, role1, other-role
-        assertEquals(3, roles.size());
-        for (BasicRole role : roles) {
-            assertTrue(role instanceof RolePrincipal);
-            if (role.getName().equals("role1")) {
-                // nested role
-                int count = 0;
-                @SuppressWarnings("rawtypes")
-                Enumeration members = role.members();
-                while (members.hasMoreElements()) {
-                    count++;
-                    assertEquals("other-role", ((Principal) members.nextElement()).getName());
-                }
-                assertEquals(1, count);
-            }
-            if (role.getName().equals("new-role")) {
-                // not nested
-                assertFalse(role.members().hasMoreElements());
-            }
-        }
-        assertTrue(roles.contains(new RolePrincipal("other-role")));
-        // role1 is not a user
-        roles = rolesAmender.getRoles("role1");
-        // expect empty
-        assertEquals(0, roles.size());
-    }
-    
-    @Test
-    public void canParseRecursiveRolesWithMultipleMemberships() {
-        rolesAmender = new RolesAmender(validFile, validUsers);
-        Set<BasicRole> roles = rolesAmender.getRoles("user2");
-        // new-role, role1, other-role
-        assertEquals(3, roles.size());
-        for (BasicRole role : roles) {
-            assertTrue(role instanceof RolePrincipal);
-            if (role.getName().equals("role1")) {
-                // nested role
-                int count = 0;
-                @SuppressWarnings("rawtypes")
-                Enumeration members = role.members();
-                while (members.hasMoreElements()) {
-                    count++;
-                    assertEquals("other-role", ((Principal) members.nextElement()).getName());
-                }
-                assertEquals(1, count);
-            }
-            if (role.getName().equals("new-role")) {
-                // not nested
-                assertFalse(role.members().hasMoreElements());
-            }
-        }
-        assertTrue(roles.contains(new RolePrincipal("other-role")));
-        // role1 is not a user
-        roles = rolesAmender.getRoles("role1");
-        // expect empty
-        assertEquals(0, roles.size());
-        // test another user which is member of the recursive role
-        roles = rolesAmender.getRoles("someuser");
-        assertEquals(
-                "Expected someuser to be a member of 'testing', 'role1' and 'other-role'",
-                3, roles.size());
-        assertTrue(roles.contains(new RolePrincipal("other-role")));
-        assertTrue(roles.contains(new RolePrincipal("testing")));
-        assertTrue(roles.contains(new RolePrincipal("role1")));
-        // and yet another user which is part of a recursive role
-        roles = rolesAmender.getRoles("someotheruser");
-        assertEquals(
-                "Expected someotheruser to be a member of 'role1' and 'other-role'",
-                2, roles.size());
-        assertTrue(roles.contains(new RolePrincipal("other-role")));
-        assertTrue(roles.contains(new RolePrincipal("role1")));
-    }
-    
-    @Test
-    public void canParseRolesWithMoreUsersThanUsedInRoles() {
-        Set<Object> users = new HashSet<>();
-        users.add("user1");
-        users.add("user2");
-        users.add("someuser");
-        users.add("someotheruser");
-        users.add("user-with-no-roles");
-        validUsers = Collections.unmodifiableSet(users);
-        try {
-            rolesAmender = new RolesAmender(validFile, validUsers);
-        } catch (Exception e) {
-            fail("should be able to parse roles");
-        }
-        Set<BasicRole> roles = rolesAmender.getRoles("user-with-no-roles");
-        assertEquals(0, roles.size());
-    }
-    
-    @Test
-    public void parseFailsIfUserInRecursiveRole() {
-        String brokenFile = decodeFilePath(this.getClass().getResource("/broken_test_roles.properties"));
-        try {
-            rolesAmender = new RolesAmender(brokenFile, validUsers);
-            fail("Should not parse");
-        } catch (Exception e) {
-            assertTrue(e instanceof IllegalStateException);
-            assertEquals("Failed to parse roles", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void parseFailsIfNotAnyUserMemberOfRecursiveRole() {
-        String brokenFile = decodeFilePath(this.getClass().getResource("/broken_test_roles2.properties"));
-        try {
-            rolesAmender = new RolesAmender(brokenFile, validUsers);
-            fail("Should not parse");
-        } catch (Exception e) {
-            assertTrue(e instanceof IllegalStateException);
-            assertEquals("Failed to parse roles", e.getMessage());
-        }
-    }
-
-    @Test
-    public void testInit() {
-        Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null);
-        try {
-            new RolesAmender(null);
-            fail("THERMOSTAT_HOME not set, should have failed!");
-        } catch (InvalidConfigurationException e) {
-            // pass
-            assertTrue(e.getMessage().contains("THERMOSTAT_HOME"));
-        }
-    }
-    
-    @Test
-    public void testInitWithMissingFile() {
-        try {
-            new RolesAmender("file/which/does/not/exist", validUsers);
-        } catch (InvalidConfigurationException e) {
-            // pass
-            assertEquals("Failed to load roles from properties", e.getMessage());
-        }
-    }
-    
-    @Test(expected = NullPointerException.class)
-    public void testInitNull() {
-        new RolesAmender("not-important", null);
-    }
-    
-    @Test
-    public void rolesInfoTest() {
-        RolePrincipal p = new RolePrincipal("test-role");
-        RolesInfo info = new RolesInfo(p);
-        assertEquals("test-role", info.getRole().getName());
-        assertEquals(0, info.getMemberUsers().size());
-        Set<String> roleMembers = info.getMemberUsers();
-        roleMembers.add("testuser");
-        assertEquals(1, info.getMemberUsers().size());
-        assertEquals(true, info.getMemberUsers().contains("testuser"));
-        roleMembers.add("testuser");
-        assertEquals(1, info.getMemberUsers().size());
-    }
-    
-    private static String decodeFilePath(URL url) {
-        try {
-            // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so
-            // as to handle cases like that.
-            return URLDecoder.decode(url.getFile(), "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new AssertionError("UTF-8 not supported, huh?");
-        }
-    }
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/SimpleCallBackHandler.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.io.IOException;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-class SimpleCallBackHandler implements CallbackHandler {
-
-    private final String username;
-    private final char[] password;
-    
-    SimpleCallBackHandler(String username) {
-        this.username = username;
-        this.password = null;
-    }
-    
-    SimpleCallBackHandler(String username, char[] password) {
-        this.username = username;
-        this.password = password;
-    }
-    
-    @Override
-    public void handle(Callback[] callbacks) throws IOException,
-            UnsupportedCallbackException {
-        for (int i = 0; i < callbacks.length; i++) {
-            Callback cb = callbacks[i];
-            if (cb instanceof NameCallback) {
-                ((NameCallback) cb).setName(username);
-            }
-            if (cb instanceof PasswordCallback) {
-                ((PasswordCallback) cb).setPassword(password);
-            }
-        }
-        
-    }
-    
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubFailureDelegateLoginModule.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.util.Map;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-public class StubFailureDelegateLoginModule implements LoginModule {
-
-    private boolean initialized = false;
-    private boolean loginCalled = false;
-    private Subject subject;
-
-    @Override
-    public void initialize(Subject subject, CallbackHandler callbackHandler,
-            Map<String, ?> sharedState, Map<String, ?> options) {
-        this.subject = subject;
-        this.initialized = true;
-    }
-
-    @Override
-    public boolean login() throws LoginException {
-        if (!initialized) {
-            throw new AssertionError("logging in when not initialized");
-        }
-        loginCalled = true;
-        throw new LoginException("Failed to login");
-    }
-
-    @Override
-    public boolean commit() throws LoginException {
-        throw new AssertionError("should never be called");
-    }
-
-    @Override
-    public boolean abort() throws LoginException {
-        if (!loginCalled) {
-            throw new AssertionError("should have called login first");
-        }
-        subject.getPrincipals().clear();
-        return true;
-    }
-
-    @Override
-    public boolean logout() throws LoginException {
-        // don't care
-        return true;
-    }
-
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubSuccessDelegateLoginModule.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.auth.spi;
-
-import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-public class StubSuccessDelegateLoginModule implements LoginModule {
-
-    private boolean initialized = false;
-    private boolean loggedIn = false;
-    private Subject subject;
-    
-    @Override
-    public void initialize(Subject subject, CallbackHandler callbackHandler,
-            Map<String, ?> sharedState, Map<String, ?> options) {
-        this.subject = subject;
-        this.initialized = true;
-    }
-
-    @Override
-    public boolean login() throws LoginException {
-        if (!initialized) {
-            throw new AssertionError("logging in when not initialized");
-        }
-        this.loggedIn = true;
-        return true;
-    }
-
-    @Override
-    public boolean commit() throws LoginException {
-        if (!loggedIn) {
-            throw new AssertionError("committing when not logged in");
-        }
-        // fake adding two principals. One user and one role
-        // principal.
-        Set<Principal> principals = this.subject.getPrincipals();
-        principals.add(new Principal() {
-
-            @Override
-            public String getName() {
-                return "testUser";
-            }
-            
-        });
-        principals.add(new Group() {
-
-            @Override
-            public String getName() {
-                return "testRole";
-            }
-
-            @Override
-            public boolean addMember(Principal user) {
-                // don't care
-                return false;
-            }
-
-            @Override
-            public boolean removeMember(Principal user) {
-                // don't care
-                return false;
-            }
-
-            @Override
-            public boolean isMember(Principal member) {
-                // don't care
-                return false;
-            }
-
-            @Override
-            public Enumeration<? extends Principal> members() {
-                Vector<Principal> stub = new Vector<>();
-                return stub.elements();
-            }
-            
-        });
-        return true;
-    }
-
-    @Override
-    public boolean abort() throws LoginException {
-        throw new AssertionError("Should never be called");
-    }
-
-    @Override
-    public boolean logout() throws LoginException {
-        return true;
-    }
-
-}
-
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/ContainerVersionTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.web.server.containers.ContainerVersion;
-
-public class ContainerVersionTest {
-
-    
-    @Test
-    public void canGetVersion() {
-        ContainerVersion version = new ContainerVersion(0, 20, 10, null);
-        assertEquals(0, version.getMajor());
-        assertEquals(20, version.getMinor());
-        assertEquals(10, version.getMicro());
-    }
-    
-    @Test
-    public void testSuffix() {
-        ContainerVersion version = new ContainerVersion(0, 20, 10, null);
-        assertEquals(ContainerVersion.UNKNOWN_SUFFIX, version.getSuffix());
-        version = new ContainerVersion(0, 20, 10, "foo");
-        assertEquals("foo", version.getSuffix());
-    }
-    
-    @Test
-    public void testToString() {
-        ContainerVersion version = new ContainerVersion(0, 20, 10, null);
-        assertEquals("0.20.10." + ContainerVersion.UNKNOWN_SUFFIX, version.toString());
-        version = new ContainerVersion(0, 20, 10, "foo");
-        assertEquals("0.20.10.foo", version.toString());
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/JettyContainerInfoTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-public class JettyContainerInfoTest {
-    
-    static final String JETTY8_SERVER_INFO = "jetty/8.1.5.v20120716";
-    static final String JETTY9_SERVER_INFO = "jetty/9.1.0.v20131115";
-
-    @Test
-    public void testParseJetty8ContainerVersion() {
-        JettyContainerInfo info = new JettyContainerInfo(JETTY8_SERVER_INFO);
-        assertEquals(ContainerName.JETTY, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNotNull(version);
-        assertEquals(8, version.getMajor());
-        assertEquals(1, version.getMinor());
-        assertEquals(5, version.getMicro());
-        assertEquals("v20120716", version.getSuffix());
-        assertEquals("8.1.5.v20120716", version.toString());
-    }
-    
-    @Test
-    public void testParseJetty9ContainerVersion() {
-        JettyContainerInfo info = new JettyContainerInfo(JETTY9_SERVER_INFO);
-        assertEquals(ContainerName.JETTY, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNotNull(version);
-        assertEquals(9, version.getMajor());
-        assertEquals(1, version.getMinor());
-        assertEquals(0, version.getMicro());
-        assertEquals("v20131115", version.getSuffix());
-        assertEquals("9.1.0.v20131115", version.toString());
-    }
-    
-    @Test
-    public void testParseEmpty() {
-        try {
-            new JettyContainerInfo("");
-            fail("should have failed to instantiate");
-        } catch (IllegalArgumentException e) {
-            assertEquals("Illegal server info: ''", e.getMessage());
-        }
-    }
-    
-    @Test
-    public void testParseNull() {
-        try {
-            new JettyContainerInfo(null);
-            fail("should have failed to instantiate");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactoryTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import org.junit.Test;
-
-public class ServletContainerInfoFactoryTest {
-   
-    @Test
-    public void canGetTomcat7ContainerInfo() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(TomcatContainerInfoTest.TOMCAT7_SERVER_INFO);
-        ServletContainerInfo info = factory.getInfo();
-        assertNotNull(info);
-        assertEquals(ContainerName.TOMCAT, info.getName());
-        assertNotNull(info.getContainerVersion());
-    }
-    
-    @Test
-    public void canGetTomcat6ContainerInfo() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(TomcatContainerInfoTest.TOMCAT6_SERVER_INFO);
-        ServletContainerInfo info = factory.getInfo();
-        assertNotNull(info);
-        assertEquals(ContainerName.TOMCAT, info.getName());
-        assertNotNull(info.getContainerVersion());
-    }
-    
-    @Test
-    public void canGetJBossAS7ContainerInfo() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(WildflyContainerInfoTest.JBOSS_AS7_SERVER_INFO);
-        ServletContainerInfo info = factory.getInfo();
-        assertNotNull(info);
-        assertEquals(ContainerName.WILDFLY, info.getName());
-        assertNotNull(info.getContainerVersion());
-    }
-    
-    @Test
-    public void canGetWildfly8ContainerInfo() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(WildflyContainerInfoTest.WILDFLY8_SERVER_INFO);
-        ServletContainerInfo info = factory.getInfo();
-        assertNotNull(info);
-        assertEquals(ContainerName.WILDFLY, info.getName());
-        assertNotNull(info.getContainerVersion());
-    }
-    
-    @Test
-    public void canGetJetty8ContainerInfo() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(JettyContainerInfoTest.JETTY8_SERVER_INFO);
-        ServletContainerInfo info = factory.getInfo();
-        assertNotNull(info);
-        assertEquals(ContainerName.JETTY, info.getName());
-        assertNotNull(info.getContainerVersion());
-    }
-    
-    @Test
-    public void canGetJetty9ContainerInfo() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory(JettyContainerInfoTest.JETTY9_SERVER_INFO);
-        ServletContainerInfo info = factory.getInfo();
-        assertNotNull(info);
-        assertEquals(ContainerName.JETTY, info.getName());
-        assertNotNull(info.getContainerVersion());
-    }
-    
-    @Test
-    public void unknownReturnsNull() {
-        ServletContainerInfoFactory factory = new ServletContainerInfoFactory("dont-know");
-        ServletContainerInfo info = factory.getInfo();
-        assertNull(info);
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfoTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-public class TomcatContainerInfoTest {
-
-    static final String TOMCAT7_SERVER_INFO = "Apache Tomcat/7.0.35";
-    static final String TOMCAT6_SERVER_INFO = "Apache Tomcat/6.0.37";
-    
-    @Test
-    public void testTomcat7ContainerInfo() {
-        ServletContainerInfo info = new TomcatContainerInfo(TOMCAT7_SERVER_INFO);
-        assertNotNull(info);
-        assertEquals(ContainerName.TOMCAT, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNotNull(version);
-        assertEquals(7, version.getMajor());
-        assertEquals(0, version.getMinor());
-        assertEquals(35, version.getMicro());
-        assertEquals(ContainerVersion.UNKNOWN_SUFFIX, version.getSuffix());
-        assertEquals("7.0.35." + ContainerVersion.UNKNOWN_SUFFIX, version.toString());
-    }
-    
-    @Test
-    public void testTomcat6ContainerInfo() {
-        ServletContainerInfo info = new TomcatContainerInfo(TOMCAT6_SERVER_INFO);
-        assertNotNull(info);
-        assertEquals(ContainerName.TOMCAT, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNotNull(version);
-        assertEquals(6, version.getMajor());
-        assertEquals(0, version.getMinor());
-        assertEquals(37, version.getMicro());
-        assertEquals(ContainerVersion.UNKNOWN_SUFFIX, version.getSuffix());
-        assertEquals("6.0.37." + ContainerVersion.UNKNOWN_SUFFIX, version.toString());
-    }
-    
-    @Test
-    public void testNull() {
-        try {
-            new TomcatContainerInfo(null);
-            fail("should have failed to instantiate");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void testEmpty() {
-        try {
-            new TomcatContainerInfo("");
-            fail("should have failed to instantiate");
-        } catch (IllegalArgumentException e) {
-            assertEquals("Illegal server info: ''", e.getMessage());
-        }
-    }
-}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfoTest.java	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright 2012-2017 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.server.containers;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-public class WildflyContainerInfoTest {
-
-    // JBoss AS uses JBoss Web as servlet container
-    static final String JBOSS_AS7_SERVER_INFO = "JBoss Web/7.0.13.Final";
-    // wildfly uses undertow as it's servlet container: see http://undertow.io/
-    static final String WILDFLY8_SERVER_INFO = "Undertow - 1.0.0.Beta17";
-    
-    @Test
-    public void testJBossAS7ContainerInfo() {
-        ServletContainerInfo info = new WildflyContainerInfo(JBOSS_AS7_SERVER_INFO);
-        assertNotNull(info);
-        assertEquals(ContainerName.WILDFLY, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNotNull(version);
-        assertEquals(7, version.getMajor());
-        assertEquals(0, version.getMinor());
-        assertEquals(13, version.getMicro());
-        assertEquals("Final", version.getSuffix());
-        assertEquals("7.0.13.Final", version.toString());
-    }
-    
-    @Test
-    public void testWildfly8ContainerInfo() {
-        ServletContainerInfo info = new WildflyContainerInfo(WILDFLY8_SERVER_INFO);
-        assertNotNull(info);
-        assertEquals(ContainerName.WILDFLY, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNotNull(version);
-        assertEquals(1, version.getMajor());
-        assertEquals(0, version.getMinor());
-        assertEquals(0, version.getMicro());
-        assertEquals("Beta17", version.getSuffix());
-        assertEquals("1.0.0.Beta17", version.toString());
-    }
-    
-    @Test
-    public void testUnknownWildflyServerInfo() {
-        ServletContainerInfo info = new WildflyContainerInfo("foo - 1.1.1.beta");
-        assertNotNull(info);
-        assertEquals(ContainerName.WILDFLY, info.getName());
-        ContainerVersion version = info.getContainerVersion();
-        assertNull(version);
-    }
-    
-    @Test
-    public void testNull() {
-        try {
-            new WildflyContainerInfo(null);
-            fail("should have failed to instantiate");
-        } catch (NullPointerException e) {
-            // pass
-        }
-    }
-    
-    @Test
-    public void testEmpty() {
-        try {
-            new WildflyContainerInfo("");
-            fail("should have failed to instantiate");
-        } catch (IllegalArgumentException e) {
-            assertEquals("Illegal server info: ''", e.getMessage());
-        }
-    }
-}
--- a/web/server/src/test/resources/broken_test_roles.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-user1 = my-role, my-role2
-user2 = new-role, role1
-role1 = other-role, user1
\ No newline at end of file
--- a/web/server/src/test/resources/broken_test_roles2.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-# Defines recursive role, but no user is a member of it.
-# Therefore, should fail to parse
-user1 = my-role, my-role2
-user2 = new-role
-role1 = other-role, user1
\ No newline at end of file
--- a/web/server/src/test/resources/properties_module_test_roles.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-user1 = my-role, my-role2
-user2 = new-role, role1
-user3 = role1
-role1 = other-role
\ No newline at end of file
--- a/web/server/src/test/resources/properties_module_test_users.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-user1 = somepassword
-user2 = password
-user3 = password
\ No newline at end of file
--- a/web/server/src/test/resources/test_roles.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-someuser = testing, role1
-user1 = my-role, my-role2
-# empty should get skipped (', ,')
-user2 = new-role, role1, ,
-role1 = other-role
-someotheruser = role1
--- a/web/server/src/test/resources/test_users.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-user1=passwd1
-# comment
-testing = password
-multiuser = blah\ntest \
-            test
-c102892{0} = test
-strange\nuser = testMe
-
-strange\0user = test\0Me
--- a/web/war/pom.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,322 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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-web</artifactId>
-    <version>1.99.12-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-war</artifactId>
-  <packaging>war</packaging>
-
-  <name>Thermostat Web WAR package</name>
-
-  <!-- context.xml config syntax changed from Tomcat 7 to Tomcat 8.
-       See: https://tomcat.apache.org/migration-8.html#Web_application_resources
-       Work around this problem by choosing the correct context.xml file at build
-       time:
-            Default        => tomcat 6, 7 compatible
-            -Dtomcat=8     => tomcat 8 compatible
-   -->
-  <profiles>
-    <profile>
-      <id>tomcat8</id>
-      <activation>
-        <property>
-          <name>tomcat</name>
-          <value>8</value>
-        </property>
-      </activation>
-      <properties>
-        <tomcat-context-xml-dir>src/main/webapp-tomcat8</tomcat-context-xml-dir>
-      </properties>
-    </profile>
-    <profile>
-      <id>tomcat-lower-8</id>
-      <activation>
-        <activeByDefault>true</activeByDefault>
-      </activation>
-      <properties>
-        <tomcat-context-xml-dir>src/main/webapp-tomcat7</tomcat-context-xml-dir>
-      </properties>
-    </profile>
-  </profiles>
-
-  <!-- The set of dependencies of the web archive should be
-       as minimal as possible. -->
-  <dependencies>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-web-server</artifactId>
-      <version>${project.version}</version>
-      <!-- exclude conflicting jars. Those cause problems for servlet
-           containers and hence prevent the web archive to deploy
-           properly  -->
-      <exclusions>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-server</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-webapp</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-servlet</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-util</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-continuation</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-http</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-io</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-security</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-xml</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-plus</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>org.eclipse.jetty</groupId>
-          <artifactId>jetty-jndi</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <!-- Plug-in dependencies:
-         Required because of model classes and
-         registries. -->
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-host-cpu-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-host-memory-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-numa-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-numa-common</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.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-classstat-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-compiler-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-byteman-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-cpu-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-gc-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-heap-analysis-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-io-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-jmx-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-memory-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-vm-profiler-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <!-- skip coverage for war -->
-      <plugin>
-        <groupId>org.jacoco</groupId>
-        <artifactId>jacoco-maven-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
-      </plugin>
-      <!-- skip tests for war -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-resources-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>move-web-resources</id>
-            <phase>generate-sources</phase>
-            <goals>
-              <goal>copy-resources</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/webapp-resources</outputDirectory>
-              <resources>          
-                <resource>
-                  <directory>src/main/webapp</directory>
-                  <!-- web.xml contains properties, which we'd like to have interpolated -->
-                  <filtering>true</filtering>
-                </resource>
-              </resources>              
-            </configuration>            
-          </execution>
-          <execution>
-            <id>move-context-xml</id>
-            <phase>process-sources</phase>
-            <goals>
-              <goal>copy-resources</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.directory}/webapp-resources</outputDirectory>
-              <resources>          
-                <resource>
-                  <directory>${tomcat-context-xml-dir}</directory>
-                  <includes>
-                    <include>**/context.xml</include>
-                  </includes>
-                </resource>
-              </resources>              
-            </configuration>            
-          </execution>
-        </executions>
-      </plugin>
-
-      <!--
-	   Package the web archive (WAR) as an exploded WAR *and WAR. Downstream
-           distributions can build and deploy the war via a maven build call similar to
-           the following (from the top level dir):
-           $ mvn -Dthermostat.web.deploy.dir=<path-to-tomcat>/webapps/thermostat clean package
-       -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-war-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>exploded-war</id>
-            <phase>package</phase>
-            <goals>
-              <goal>exploded</goal>
-            </goals>
-            <configuration>
-              <warSourceDirectory>${project.build.directory}/webapp-resources</warSourceDirectory>
-              <webXml>${project.build.directory}/webapp-resources/WEB-INF/web.xml</webXml>
-              <webappDirectory>${thermostat.web.deploy.dir}</webappDirectory>
-            </configuration>
-          </execution>
-          <execution>
-            <id>war</id>
-            <phase>package</phase>
-            <goals>
-              <goal>war</goal>
-            </goals>
-            <configuration>
-              <warSourceDirectory>${project.build.directory}/webapp-resources</warSourceDirectory>
-              <webXml>${project.build.directory}/webapp-resources/WEB-INF/web.xml</webXml>
-              <!-- Required for the embedded servlet endpoint plugin. -->
-              <attachClasses>true</attachClasses>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-
-</project>
-
--- a/web/war/src/main/resources/logging.properties	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-# Copyright 2012-2014 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.
-
-###################################################################
-# Thermostat web service (war in tomcat) logging configuration
-###################################################################
-
-handlers = org.apache.juli.FileHandler
-
-############################################################
-# Handler specific properties.
-# Describes specific configuration info for Handlers.
-############################################################
-
-org.apache.juli.FileHandler.level = FINEST
-org.apache.juli.FileHandler.directory = ${catalina.base}/logs
-org.apache.juli.FileHandler.prefix = thermostat-web-storage.
-
-com.redhat.thermostat.handlers = org.apache.juli.FileHandler
-com.redhat.thermostat.level = FINEST
-
--- a/web/war/src/main/webapp-tomcat7/META-INF/context.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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.
-
--->
-<!-- allow symlinks to /usr/share/java deps in WEB-INF/lib -->
-<Context path="/thermostat" allowLinking="true">
-       <!-- Configures JAAS for Tomcat -->
-       <Realm className="org.apache.catalina.realm.JAASRealm"                 
-               appName="ThermostatJAASLogin"       
-               userClassNames="com.redhat.thermostat.web.server.auth.UserPrincipal"       
-               roleClassNames="com.redhat.thermostat.web.server.auth.WrappedRolePrincipal,
-                               com.redhat.thermostat.web.server.auth.RolePrincipal"/>
-</Context>
--- a/web/war/src/main/webapp-tomcat8/META-INF/context.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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.
-
--->
-<Context path="/thermostat">
-       <!-- allow symlinks to /usr/share/java deps in WEB-INF/lib -->
-       <Resources allowLinking="true"/>
-       <!-- Configures JAAS for Tomcat -->
-       <Realm className="org.apache.catalina.realm.JAASRealm"                 
-               appName="ThermostatJAASLogin"       
-               userClassNames="com.redhat.thermostat.web.server.auth.UserPrincipal"       
-               roleClassNames="com.redhat.thermostat.web.server.auth.WrappedRolePrincipal,
-                               com.redhat.thermostat.web.server.auth.RolePrincipal"/>
-</Context>
--- a/web/war/src/main/webapp/WEB-INF/jetty-web.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-<?xml version="1.0"  encoding="UTF-8"?>
-<!--
-
- Copyright 2012-2017 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.
-
--->
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
-
-<!-- ==================================================================
-Thermostat JAAS configuration for jetty. This tells jetty that
-it should use JAAS for the "Thermostat Realm". It is imperative that
-the realm name matches. It also tells jetty which classes map to
-role principals and set the name of the JAAS config entry to use.
-
-This should work with Jetty 8.
-
-===================================================================== -->
-
-<Configure class="org.eclipse.jetty.webapp.WebAppContext">
-  <Set name="contextPath">/thermostat</Set>
-  <Get name="securityHandler">
-    <Set name="loginService">
-      <New class="org.eclipse.jetty.jaas.JAASLoginService">
-            <Set name="name">Thermostat Realm</Set>
-            <Set name="loginModuleName">ThermostatJAASLogin</Set>
-            <Set name="roleClassNames">
-              <Array type="java.lang.String">
-                <Item>com.redhat.thermostat.web.server.auth.RolePrincipal</Item>
-                <Item>com.redhat.thermostat.web.server.auth.WrappedRolePrincipal</Item>
-              </Array>
-            </Set>
-      </New>
-    </Set>
-  </Get>
-</Configure>
--- a/web/war/src/main/webapp/WEB-INF/web.xml	Tue Mar 21 18:40:40 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-<!--
-
- Copyright 2012-2017 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.
-
--->
-<!DOCTYPE web-app PUBLIC
- "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd" >
-
-<web-app>
-
-  <display-name>Thermostat Web Service</display-name>
-  <description>Thermostat Web Service</description> 
-  <servlet>
-    <init-param>
-      <param-name>storage.class</param-name>
-      <param-value>com.redhat.thermostat.storage.mongodb.MongoStorageProvider</param-value>
-    </init-param>
-    <init-param>
-      <param-name>storage.endpoint</param-name>
-      <param-value>mongodb://127.0.0.1:27518</param-value>
-    </init-param>
-    <!-- The timeout of the token manager in ms -->
-    <init-param>
-      <param-name>token-manager-timeout</param-name>
-      <param-value>3000</param-value>
-    </init-param>
-    <servlet-name>reststorage-servlet</servlet-name>
-    <servlet-class>com.redhat.thermostat.web.server.WebStorageEndPoint</servlet-class>
-  </servlet>
-
-  <servlet-mapping>
-    <servlet-name>reststorage-servlet</servlet-name>
-    <url-pattern>/storage/*</url-pattern>
-  </servlet-mapping>
-
-  <security-constraint>
-    <web-resource-collection>
-      <web-resource-name>Entire Application</web-resource-name>
-      <url-pattern>/*</url-pattern>
-    </web-resource-collection>
-    <auth-constraint>
-      <role-name>thermostat-realm</role-name>
-    </auth-constraint>
-  </security-constraint>
-
-  <login-config>
-    <auth-method>BASIC</auth-method>
-    <realm-name>Thermostat Realm</realm-name>
-  </login-config>
-
-  <security-role>
-    <role-name>thermostat-realm</role-name>
-  </security-role>
-  
-  <!--
-    The system property THERMOSTAT_HOME is set via the listener below.
-    This hard-coded value is only used if this war is deployed into a web
-    server. It is ignored if the thermostat command is used to run this war
-    inside an embedded server.
-  -->
-  <context-param>
-    <param-name>THERMOSTAT_HOME</param-name>
-    <param-value>${thermostat.home}</param-value>
-  </context-param>
-  
-  <listener>
-    <listener-class>com.redhat.thermostat.web.server.PropertySettingServletContextListener</listener-class>
-  </listener>
-
-</web-app>