changeset 2634:ffe33cda8003

Update HostInfoDAO to communicate with web gateway Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/022938.html
author Elliott Baron <ebaron@redhat.com>
date Fri, 05 May 2017 12:27:50 -0400
parents 1887270ae88b
children 543cd4a5912a
files plugins/com.redhat.thermostat.host.overview/agent/src/test/java/com/redhat/thermostat/host/overview/agent/internal/HostInfoBuilderTest.java plugins/com.redhat.thermostat.host.overview/common/pom.xml plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/HostInfoDAO.java plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImpl.java plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImplStatementDescriptorRegistration.java plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoTypeAdapter.java plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImplStatementDescriptorRegistrationTest.java plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOTest.java plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoTypeAdapterTest.java
diffstat 9 files changed, 357 insertions(+), 346 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/com.redhat.thermostat.host.overview/agent/src/test/java/com/redhat/thermostat/host/overview/agent/internal/HostInfoBuilderTest.java	Fri May 05 12:12:46 2017 -0400
+++ b/plugins/com.redhat.thermostat.host.overview/agent/src/test/java/com/redhat/thermostat/host/overview/agent/internal/HostInfoBuilderTest.java	Fri May 05 12:27:50 2017 -0400
@@ -37,15 +37,18 @@
 package com.redhat.thermostat.host.overview.agent.internal;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
 import com.redhat.thermostat.common.portability.PortableHost;
 import com.redhat.thermostat.host.overview.agent.internal.models.HostInfoBuilder;
 import com.redhat.thermostat.host.overview.common.model.HostInfo;
+import com.redhat.thermostat.shared.config.OS;
 import com.redhat.thermostat.storage.core.WriterID;
 
 public class HostInfoBuilderTest {
--- a/plugins/com.redhat.thermostat.host.overview/common/pom.xml	Fri May 05 12:12:46 2017 -0400
+++ b/plugins/com.redhat.thermostat.host.overview/common/pom.xml	Fri May 05 12:27:50 2017 -0400
@@ -136,6 +136,20 @@
       <version>${project.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-client</artifactId>
+    </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>
     <!-- declarative services -->
     <dependency>
       <groupId>org.apache.felix</groupId>
--- a/plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/HostInfoDAO.java	Fri May 05 12:12:46 2017 -0400
+++ b/plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/HostInfoDAO.java	Fri May 05 12:27:50 2017 -0400
@@ -36,17 +36,13 @@
 
 package com.redhat.thermostat.host.overview.common;
 
-import java.util.List;
-
 import com.redhat.thermostat.annotations.Service;
 import com.redhat.thermostat.host.overview.common.model.HostInfo;
-import com.redhat.thermostat.storage.core.AgentId;
 import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Countable;
 import com.redhat.thermostat.storage.core.Key;
 
 @Service
-public interface HostInfoDAO extends Countable {
+public interface HostInfoDAO {
 
     static Key<String> hostNameKey = new Key<>("hostname");
     static Key<String> osNameKey = new Key<>("osName");
@@ -59,17 +55,6 @@
             Key.AGENT_ID, hostNameKey, osNameKey, osKernelKey,
             cpuCountKey, cpuModelKey, hostMemoryTotalKey);
 
-    /** @return information on all known hosts */
-    List<HostInfo> getAllHostInfos();
-
-    /**
-     *
-     * @param agentId The Agent Id for which to get the HostInfo object for.
-     * @return The corresponding HostInfo object. May return null if the user
-     *         is not permitted to retrieve this HostInfo.
-     */
-    HostInfo getHostInfo(AgentId agentId);
-
     void putHostInfo(HostInfo info);
 
 }
--- a/plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImpl.java	Fri May 05 12:12:46 2017 -0400
+++ b/plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImpl.java	Fri May 05 12:27:50 2017 -0400
@@ -36,122 +36,150 @@
 
 package com.redhat.thermostat.host.overview.common.internal;
 
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpContentResponse;
+import org.eclipse.jetty.client.HttpRequest;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.host.overview.common.HostInfoDAO;
 import com.redhat.thermostat.host.overview.common.model.HostInfo;
-import com.redhat.thermostat.storage.core.AgentId;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.CategoryAdapter;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
-import com.redhat.thermostat.storage.dao.AbstractDaoStatement;
-import com.redhat.thermostat.storage.dao.BaseCountable;
-import com.redhat.thermostat.storage.dao.SimpleDaoQuery;
-import com.redhat.thermostat.storage.model.AggregateCount;
 
 @Component
 @Service(value = HostInfoDAO.class)
-public class HostInfoDAOImpl extends BaseCountable implements HostInfoDAO {
+public class HostInfoDAOImpl implements HostInfoDAO {
     
     private static final Logger logger = LoggingUtils.getLogger(HostInfoDAOImpl.class);
-    static final String QUERY_HOST_INFO = "QUERY "
-            + hostInfoCategory.getName() + " WHERE '"
-            + Key.AGENT_ID.getName() + "' = ?s LIMIT 1";
-    static final String QUERY_ALL_HOSTS = "QUERY " + hostInfoCategory.getName();
-    // We can use hostInfoCategory.getName() here since this query
-    // only changes the data class. When executed we use the adapted
-    // aggregate category.
-    static final String AGGREGATE_COUNT_ALL_HOSTS = "QUERY-COUNT " + hostInfoCategory.getName();
-    // ADD host-info SET 'agentId' = ?s , \
-    //                   'hostname' = ?s , \
-    //                   'osName' = ?s , \
-    //                   'osKernel' = ?s , \
-    //                   'cpuModel' = ?s , \
-    //                   'cpuCount' = ?i , \
-    //                   'totalMemory' = ?l
-    static final String DESC_ADD_HOST_INFO = "ADD " + hostInfoCategory.getName() +
-            " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
-                 "'" + hostNameKey.getName() + "' = ?s , " +
-                 "'" + osNameKey.getName() + "' = ?s , " +
-                 "'" + osKernelKey.getName() + "' = ?s , " +
-                 "'" + cpuModelKey.getName() + "' = ?s , " +
-                 "'" + cpuCountKey.getName() + "' = ?i , " +
-                 "'" + hostMemoryTotalKey.getName() + "' = ?l";
+    
+    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
+    private static final String GATEWAY_PATH = "/host-info/systems/*/agents/";
+    private static final String CONTENT_TYPE = "application/json";
 
-    private final Category<AggregateCount> aggregateCategory;
+    private final JsonHelper jsonHelper;
+    private final HttpHelper httpHelper;
     
-    @Reference
-    private Storage storage;
-
     public HostInfoDAOImpl() {
-        this(null);
+        this(new HttpHelper(new HttpClient()), new JsonHelper(new HostInfoTypeAdapter()));
     }
     
-    public HostInfoDAOImpl(Storage storage) {
-        this.storage = storage;
-        // Adapt category to the aggregate form
-        CategoryAdapter<HostInfo, AggregateCount> adapter = new CategoryAdapter<>(hostInfoCategory);
-        this.aggregateCategory = adapter.getAdapted(AggregateCount.class);
+    HostInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) {
+        this.httpHelper = httpHelper;
+        this.jsonHelper = jsonHelper;
     }
     
     @Activate
-    private void activate() {
-        storage.registerCategory(hostInfoCategory);
-        storage.registerCategory(aggregateCategory);
-    }
-
-    @Override
-    public HostInfo getHostInfo(final AgentId agentId) {
-        return executeQuery(new AbstractDaoQuery<HostInfo>(storage, hostInfoCategory, QUERY_HOST_INFO) {
-            @Override
-            public PreparedStatement<HostInfo> customize(PreparedStatement<HostInfo> preparedStatement) {
-                preparedStatement.setString(0, agentId.get());
-                return preparedStatement;
-            }
-        }).head();
+    void activate() throws Exception {
+        httpHelper.startClient();
     }
 
     @Override
     public void putHostInfo(final HostInfo info) {
-        executeStatement(new AbstractDaoStatement<HostInfo>(storage, hostInfoCategory, DESC_ADD_HOST_INFO) {
-            @Override
-            public PreparedStatement<HostInfo> customize(PreparedStatement<HostInfo> preparedStatement) {
-                preparedStatement.setString(0, info.getAgentId());
-                preparedStatement.setString(1, info.getHostname());
-                preparedStatement.setString(2, info.getOsName());
-                preparedStatement.setString(3, info.getOsKernel());
-                preparedStatement.setString(4, info.getCpuModel());
-                preparedStatement.setInt(5, info.getCpuCount());
-                preparedStatement.setLong(6, info.getTotalMemory());
-                return preparedStatement;
+        try {
+            String json = jsonHelper.toJson(Arrays.asList(info));
+            StringContentProvider provider = httpHelper.createContentProvider(json);
+            String url = getURL(info.getAgentId());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.POST);
+            httpRequest.content(provider, CONTENT_TYPE);
+            ContentResponse resp = httpRequest.send();
+            int status = resp.getStatus();
+            if (status != HttpStatus.OK_200) {
+                throw new IOException("Gateway returned HTTP status " + String.valueOf(status) + " - " + resp.getReason());
             }
-        });
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to send host information to web gateway", e);
+        }
     }
 
-    @Override
-    public List<HostInfo> getAllHostInfos() {
-        return executeQuery(new SimpleDaoQuery<>(storage, hostInfoCategory, QUERY_ALL_HOSTS)).asList();
+    private String getURL(String agentId) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(GATEWAY_URL);
+        builder.append(GATEWAY_PATH);
+        builder.append(agentId);
+        return builder.toString();
     }
-
-    @Override
-    public long getCount() {
-        return getCount(storage, aggregateCategory, AGGREGATE_COUNT_ALL_HOSTS);
+    
+    // For testing purposes
+    static class JsonHelper {
+        
+        private final HostInfoTypeAdapter typeAdapter;
+        
+        public JsonHelper(HostInfoTypeAdapter typeAdapter) {
+            this.typeAdapter = typeAdapter;
+        }
+        
+        String toJson(List<HostInfo> infos) throws IOException {
+            return typeAdapter.toJson(infos);
+        }
+        
     }
     
-    @Override
-    protected Logger getLogger() {
-        return logger;
+    // For testing purposes
+    static class HttpHelper {
+        
+        private final HttpClient httpClient;
+
+        HttpHelper(HttpClient httpClient) {
+            this.httpClient = httpClient;
+        }
+        
+        void startClient() throws Exception {
+            httpClient.start();
+        }
+        
+        StringContentProvider createContentProvider(String content) {
+            return new StringContentProvider(content);
+        }
+        
+        Request newRequest(String url) {
+            return new MockRequest(httpClient, URI.create(url));
+        }
+        
     }
+    
+    // FIXME This class should be removed when the web gateway has a microservice for this DAO
+    private static class MockRequest extends HttpRequest {
 
+        MockRequest(HttpClient client, URI uri) {
+            super(client, uri);
+        }
+        
+        @Override
+        public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException {
+            return new MockResponse();
+        }
+        
+    }
+    
+    // FIXME This class should be removed when the web gateway has a microservice for this DAO
+    private static class MockResponse extends HttpContentResponse {
+
+        MockResponse() {
+            super(null, null, null);
+        }
+        
+        @Override
+        public int getStatus() {
+            return HttpStatus.OK_200;
+        }
+        
+    }
+    
 }
 
--- a/plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImplStatementDescriptorRegistration.java	Fri May 05 12:12:46 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +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.host.overview.common.internal;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
-
-/**
- * Registers the prepared query issued by this maven module via
- * {@link HostLatestPojoListGetter}.
- *
- */
-public class HostInfoDAOImplStatementDescriptorRegistration implements
-        StatementDescriptorRegistration {
-    
-    @Override
-    public Set<String> getStatementDescriptors() {
-        Set<String> descs = new HashSet<>(4);
-        descs.add(HostInfoDAOImpl.QUERY_HOST_INFO);
-        descs.add(HostInfoDAOImpl.QUERY_ALL_HOSTS);
-        descs.add(HostInfoDAOImpl.AGGREGATE_COUNT_ALL_HOSTS);
-        descs.add(HostInfoDAOImpl.DESC_ADD_HOST_INFO);
-        return descs;
-    }
-
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/com.redhat.thermostat.host.overview/common/src/main/java/com/redhat/thermostat/host/overview/common/internal/HostInfoTypeAdapter.java	Fri May 05 12:27:50 2017 -0400
@@ -0,0 +1,105 @@
+/*
+ * 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.host.overview.common.internal;
+
+import java.io.IOException;
+import java.util.List;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+import com.redhat.thermostat.host.overview.common.model.HostInfo;
+
+public class HostInfoTypeAdapter extends TypeAdapter<List<HostInfo>> {
+    
+    private static final String AGENT_ID = "agentId";
+    private static final String HOSTNAME = "hostname";
+    private static final String OS_NAME = "osName";
+    private static final String OS_KERNEL = "osKernel";
+    private static final String CPU_MODEL = "cpuModel";
+    private static final String CPU_COUNT = "cpuCount";
+    private static final String TOTAL_MEMORY = "totalMemory";
+    private static final String TYPE_LONG = "$numberLong";
+
+    @Override
+    public void write(JsonWriter out, List<HostInfo> value) throws IOException {
+        // Request is an array of HostInfo objects
+        out.beginArray();
+        
+        for (HostInfo info : value) {
+            writeHostInfo(out, info);
+        }
+        
+        out.endArray();
+    }
+
+    private void writeHostInfo(JsonWriter out, HostInfo info) throws IOException {
+        out.beginObject();
+        
+        // Write each field of HostInfo as part of a JSON object
+        out.name(AGENT_ID);
+        out.value(info.getAgentId());
+        out.name(HOSTNAME);
+        out.value(info.getHostname());
+        out.name(OS_NAME);
+        out.value(info.getOsName());
+        out.name(OS_KERNEL);
+        out.value(info.getOsKernel());
+        out.name(CPU_MODEL);
+        out.value(info.getCpuModel());
+        out.name(CPU_COUNT);
+        out.value(info.getCpuCount());
+        out.name(TOTAL_MEMORY);
+        writeLong(out, info.getTotalMemory());
+        
+        out.endObject();
+    }
+
+    private void writeLong(JsonWriter out, long totalMemory) throws IOException {
+        // Write MongoDB representation of a Long
+        out.beginObject();
+        out.name(TYPE_LONG);
+        out.value(String.valueOf(totalMemory));
+        out.endObject();
+    }
+
+    @Override
+    public List<HostInfo> read(JsonReader in) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+}
--- a/plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOImplStatementDescriptorRegistrationTest.java	Fri May 05 12:12:46 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.host.overview.common.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import java.util.Set;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.host.overview.common.internal.HostInfoDAOImplStatementDescriptorRegistration;
-import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
-import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
-import com.redhat.thermostat.testutils.ServiceLoaderTest;
-
-public class HostInfoDAOImplStatementDescriptorRegistrationTest extends ServiceLoaderTest<StatementDescriptorRegistration> {
-
-    public HostInfoDAOImplStatementDescriptorRegistrationTest() {
-        super(StatementDescriptorRegistration.class, STORAGE_SERVICES, DAOImplStatementDescriptorRegistration.class);
-    }
-
-    @Test
-    public void registersAllDescriptors() {
-        HostInfoDAOImplStatementDescriptorRegistration reg = new HostInfoDAOImplStatementDescriptorRegistration();
-        Set<String> descriptors = reg.getStatementDescriptors();
-        assertEquals(4, descriptors.size());
-        assertFalse("null descriptor not allowed", descriptors.contains(null));
-    }
-
-}
-
--- a/plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOTest.java	Fri May 05 12:12:46 2017 -0400
+++ b/plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoDAOTest.java	Fri May 05 12:27:50 2017 -0400
@@ -37,72 +37,68 @@
 package com.redhat.thermostat.host.overview.common.internal;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.NoSuchElementException;
 
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 
 import com.redhat.thermostat.host.overview.common.HostInfoDAO;
+import com.redhat.thermostat.host.overview.common.internal.HostInfoDAOImpl.HttpHelper;
+import com.redhat.thermostat.host.overview.common.internal.HostInfoDAOImpl.JsonHelper;
 import com.redhat.thermostat.host.overview.common.model.HostInfo;
-import com.redhat.thermostat.storage.core.AgentId;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.AggregateCount;
 
 public class HostInfoDAOTest {
 
-    static class Triple<S, T, U> {
-        final S first;
-        final T second;
-        final U third;
-
-        public Triple(S first, T second, U third) {
-            this.first = first;
-            this.second = second;
-            this.third = third;
-        }
-    }
-
+    private static final String URL = "http://localhost:26000/api/v100/host-info/systems/*/agents/foo-agent";
+    private static final String SOME_JSON = "{\"some\" : \"json\"}";
     private static final String HOST_NAME = "a host name";
     private static final String OS_NAME = "some os";
     private static final String OS_KERNEL = "some kernel";
     private static final String CPU_MODEL = "some cpu that runs fast";
     private static final int CPU_NUM = -1;
     private static final long MEMORY_TOTAL = 0xCAFEBABEl;
+    private static final String CONTENT_TYPE = "application/json";
+    
+    private HostInfo info;
+    private JsonHelper jsonHelper;
+    private HttpHelper httpHelper;
+    private StringContentProvider contentProvider;
+    private Request request;
+    private ContentResponse response;
+    
+    @Before
+    public void setup() throws Exception {
+        info = new HostInfo("foo-agent", HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
+        
+        httpHelper = mock(HttpHelper.class);
+        contentProvider = mock(StringContentProvider.class);
+        when(httpHelper.createContentProvider(anyString())).thenReturn(contentProvider);
+        request = mock(Request.class);
+        when(httpHelper.newRequest(anyString())).thenReturn(request);
+        response = mock(ContentResponse.class);
+        when(response.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(request.send()).thenReturn(response);
+        
+        jsonHelper = mock(JsonHelper.class);
+        when(jsonHelper.toJson(anyListOf(HostInfo.class))).thenReturn(SOME_JSON);
+    }
 
     @Test
-    public void preparedQueryDescriptorsAreSane() {
-        String expectedHostInfo = "QUERY host-info WHERE 'agentId' = ?s LIMIT 1";
-        assertEquals(expectedHostInfo, HostInfoDAOImpl.QUERY_HOST_INFO);
-        String expectedAllHosts = "QUERY host-info";
-        assertEquals(expectedAllHosts, HostInfoDAOImpl.QUERY_ALL_HOSTS);
-        String aggregateAllHosts = "QUERY-COUNT host-info";
-        assertEquals(aggregateAllHosts, HostInfoDAOImpl.AGGREGATE_COUNT_ALL_HOSTS);
-        String addHostInfo = "ADD host-info SET 'agentId' = ?s , " +
-                                                  "'hostname' = ?s , " +
-                                                  "'osName' = ?s , " +
-                                                  "'osKernel' = ?s , " +
-                                                  "'cpuModel' = ?s , " +
-                                                  "'cpuCount' = ?i , " +
-                                                  "'totalMemory' = ?l";
-        assertEquals(addHostInfo, HostInfoDAOImpl.DESC_ADD_HOST_INFO);
-    }
-    
-    @Test
     public void testCategory() {
         assertEquals("host-info", HostInfoDAO.hostInfoCategory.getName());
         Collection<Key<?>> keys = HostInfoDAO.hostInfoCategory.getKeys();
@@ -117,84 +113,19 @@
     }
 
     @Test
-    public void testGetHostInfoUsingAgentId() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<HostInfo> prepared = (PreparedStatement<HostInfo>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(prepared);
-
-        HostInfo info = new HostInfo("foo-agent", HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        @SuppressWarnings("unchecked")
-        Cursor<HostInfo> cursor = (Cursor<HostInfo>) mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(info).thenReturn(null);
-        when(prepared.executeQuery()).thenReturn(cursor);
-
-        HostInfo result = new HostInfoDAOImpl(storage).getHostInfo(new AgentId("some uid"));
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(prepared).setString(0, "some uid");
-        verify(prepared).executeQuery();
-        assertSame(result, info);
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<HostInfo> anyDescriptor() {
-        return (StatementDescriptor<HostInfo>) any(StatementDescriptor.class);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testPutHostInfo() throws DescriptorParsingException,
-            StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        PreparedStatement<HostInfo> add = mock(PreparedStatement.class);
-        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
-
-        HostInfo info = new HostInfo("foo-agent", HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL);
-        HostInfoDAO dao = new HostInfoDAOImpl(storage);
+    public void testPutHostInfo() throws Exception {
+        HostInfoDAOImpl dao = new HostInfoDAOImpl(httpHelper, jsonHelper);
+        dao.activate();
         dao.putHostInfo(info);
         
-        @SuppressWarnings("rawtypes")
-        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
-
-        verify(storage).prepareStatement(captor.capture());
-        StatementDescriptor<?> desc = captor.getValue();
-        assertEquals(HostInfoDAOImpl.DESC_ADD_HOST_INFO, desc.getDescriptor());
-        
-        verify(add).setString(0, info.getAgentId());
-        verify(add).setString(1, info.getHostname());
-        verify(add).setString(2, info.getOsName());
-        verify(add).setString(3, info.getOsKernel());
-        verify(add).setString(4, info.getCpuModel());
-        verify(add).setInt(5, info.getCpuCount());
-        verify(add).setLong(6, info.getTotalMemory());
-        verify(add).execute();
-        Mockito.verifyNoMoreInteractions(add);
+        verify(httpHelper).newRequest(URL);
+        verify(request).method(HttpMethod.POST);
+        verify(jsonHelper).toJson(eq(Arrays.asList(info)));
+        verify(httpHelper).createContentProvider(SOME_JSON);
+        verify(request).content(contentProvider, CONTENT_TYPE);
+        verify(request).send();
+        verify(response).getStatus();
     }
 
-    @Test
-    public void testGetCount() throws DescriptorParsingException,
-            StatementExecutionException {
-        AggregateCount count = new AggregateCount();
-        count.setCount(2);
-
-        @SuppressWarnings("unchecked")
-        Cursor<AggregateCount> c = (Cursor<AggregateCount>) mock(Cursor.class);
-        when(c.hasNext()).thenReturn(true).thenReturn(false);
-        when(c.next()).thenReturn(count).thenThrow(new NoSuchElementException());
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<AggregateCount> stmt = (PreparedStatement<AggregateCount>) mock(PreparedStatement.class);
-        @SuppressWarnings("unchecked")
-        StatementDescriptor<AggregateCount> desc = any(StatementDescriptor.class);
-        when(storage.prepareStatement(desc)).thenReturn(stmt);
-        when(stmt.executeQuery()).thenReturn(c);
-        HostInfoDAOImpl dao = new HostInfoDAOImpl(storage);
-
-        assertEquals(2, dao.getCount());
-    }
-    
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/com.redhat.thermostat.host.overview/common/src/test/java/com/redhat/thermostat/host/overview/common/internal/HostInfoTypeAdapterTest.java	Fri May 05 12:27:50 2017 -0400
@@ -0,0 +1,75 @@
+/*
+ * 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.host.overview.common.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.host.overview.common.model.HostInfo;
+
+public class HostInfoTypeAdapterTest {
+    
+    private HostInfoTypeAdapter adapter;
+    
+    @Before
+    public void setup() {
+        adapter = new HostInfoTypeAdapter();
+    }
+
+    @Test
+    public void testWrite() throws Exception {
+        final String expected = "[{\"agentId\":\"myAgent1\",\"hostname\":\"myHost1\"," 
+                + "\"osName\":\"myOS1\",\"osKernel\":\"myKernel1\",\"cpuModel\":\"myCPU1\"," 
+                + "\"cpuCount\":4,\"totalMemory\":{\"$numberLong\":\"400000000\"}}," 
+                + "{\"agentId\":\"myAgent2\",\"hostname\":\"myHost2\",\"osName\":\"myOS2\"," 
+                + "\"osKernel\":\"myKernel2\",\"cpuModel\":\"myCPU2\",\"cpuCount\":2," 
+                + "\"totalMemory\":{\"$numberLong\":\"800000000\"}}]";
+        
+        HostInfo first = new HostInfo("myAgent1", "myHost1", "myOS1", "myKernel1", "myCPU1", 4, 400000000L);
+        HostInfo second = new HostInfo("myAgent2", "myHost2", "myOS2", "myKernel2", "myCPU2", 2, 800000000L);
+        List<HostInfo> infos = Arrays.asList(first, second);
+        
+        String json = adapter.toJson(infos);
+        assertEquals(expected, json);
+    }
+
+}