changeset 2695:9dbdade820ce

AgentDao and backend should be in agent, not storage-core review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-June/023778.html reviewed-by: jerboaa
author Mario Torre <neugens.limasoftware@gmail.com>
date Tue, 20 Jun 2017 13:00:11 +0200
parents 80b17b58e7a7
children ed4beec29d96
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/Activator.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java agent/core/pom.xml agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java agent/core/src/main/java/com/redhat/thermostat/agent/dao/AgentInfoDAO.java agent/core/src/main/java/com/redhat/thermostat/agent/dao/BackendInfoDAO.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/AgentInfoDAOImpl.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/AgentInformationTypeAdapter.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/BackendInfoDAOImpl.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/BackendInformationTypeAdapter.java agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/AgentInfoDAOTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/AgentInformationTypeAdapterTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/BackendInfoDAOTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/BackendInformationTypeAdapterTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/BackendInfoDAO.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapter.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapter.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapterTest.java
diffstat 31 files changed, 1335 insertions(+), 1355 deletions(-) [+]
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/Activator.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/Activator.java	Tue Jun 20 13:00:11 2017 +0200
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.agent.cli.internal;
 
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 
@@ -61,7 +63,9 @@
         Class<?>[] deps = new Class<?>[] {
                 ExitStatus.class,
                 WriterID.class,
-                SSLConfiguration.class
+                SSLConfiguration.class,
+                AgentInfoDAO.class,
+                BackendInfoDAO.class,
         };
         tracker = new MultipleServiceTracker(context, deps, new Action() {
             
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java	Tue Jun 20 13:00:11 2017 +0200
@@ -40,6 +40,8 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.osgi.framework.BundleContext;
 import org.osgi.util.tracker.ServiceTracker;
 
@@ -62,9 +64,6 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.BackendInfoDAO;
-
 import sun.misc.Signal;
 import sun.misc.SignalHandler;
 
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -48,6 +48,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -73,8 +75,6 @@
 import com.redhat.thermostat.common.cli.CommandException;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
 
--- a/agent/core/pom.xml	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/core/pom.xml	Tue Jun 20 13:00:11 2017 +0200
@@ -121,6 +121,7 @@
             <Export-Package>
                 com.redhat.thermostat.agent,
                 com.redhat.thermostat.agent.config,
+                com.redhat.thermostat.agent.dao,
                 com.redhat.thermostat.agent.utils,
                 com.redhat.thermostat.agent.utils.management,
                 com.redhat.thermostat.backend
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Tue Jun 20 13:00:11 2017 +0200
@@ -43,6 +43,8 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.agent.config.AgentStartupConfiguration;
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendRegistry;
 import com.redhat.thermostat.common.ActionEvent;
@@ -51,8 +53,6 @@
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.BackendInformation;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/dao/AgentInfoDAO.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,94 @@
+/*
+ * 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.agent.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import com.redhat.thermostat.annotations.Service;
+import com.redhat.thermostat.storage.core.AgentId;
+import com.redhat.thermostat.storage.model.AgentInformation;
+
+/**
+ * Access information about agents that agents publish to storage.
+ */
+@Service
+public interface AgentInfoDAO {
+    
+    /**
+     * Get information about all known agents.
+     *
+     * @return a {@link List} of {@link AgentInformation} for all agents
+     * who have published their information. Will be empty if there is no
+     * information.
+     */
+    List<AgentInformation> getAllAgentInformation();
+
+    /**
+     * Get information about a specific agent.
+     *
+     * @return a {@link AgentInformation} describing information about the agent
+     * indicated by {@code agentId}. {@code null} if no information about the
+     * agent could be located.
+     */
+
+    AgentInformation getAgentInformation(AgentId agentId);
+
+    /**
+     *
+     * @return A set of AgentIds, which may be empty.
+     */
+    Set<AgentId> getAgentIds();
+
+    /**
+     * Publish information about agent into the storage.
+     */
+    void addAgentInformation(AgentInformation agentInfo);
+
+    /**
+     * Update information about an existing agent. No changes will be performed
+     * if there is no matching agent.
+     */
+    void updateAgentInformation(AgentInformation agentInfo);
+
+    /**
+     * Remove information about an agent that was published to storage.
+     */
+    void removeAgentInformation(AgentInformation agentInfo);
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/dao/BackendInfoDAO.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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.agent.dao;
+
+import com.redhat.thermostat.annotations.Service;
+import com.redhat.thermostat.storage.model.BackendInformation;
+
+@Service
+public interface BackendInfoDAO {
+
+    void addBackendInformation(BackendInformation info);
+
+    void removeBackendInformation(BackendInformation info);
+
+}
+
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Tue Jun 20 13:00:11 2017 +0200
@@ -40,6 +40,8 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -70,7 +72,7 @@
 
     @Override
     public void start(final BundleContext context) throws Exception {
-        
+
         // Track common paths separately and register storage credentials quickly
         // We need to do this since otherwise no storage credentials will be
         // available by the time they're used in DbService
@@ -81,9 +83,7 @@
                 CommonPaths paths = context.getService(ref);
                 try {
                     AgentConfigsUtils.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile());
-//                    VmBlacklistImpl blacklist = new VmBlacklistImpl();
-//                    blacklist.addVmFilter(new AgentProxyFilter());
-//                    context.registerService(VmBlacklist.class, blacklist, null);
+
                 } catch (InvalidConfigurationException e) {
                     logger.log(Level.SEVERE, "Failed to start agent services", e);
                 }
@@ -107,6 +107,18 @@
             
             @Override
             public void dependenciesAvailable(DependencyProvider services) {
+
+                try {
+                    AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl();
+                    context.registerService(AgentInfoDAO.class, agentInfoDAO, null);
+
+                    BackendInfoDAO backendInfoDAO = new BackendInfoDAOImpl();
+                    context.registerService(BackendInfoDAO.class, backendInfoDAO, null);
+
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+
                 AgentIPCService ipcService = services.get(AgentIPCService.class);
                 CommonPaths paths = services.get(CommonPaths.class);
                 UserNameUtil util = services.get(UserNameUtil.class);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/AgentInfoDAOImpl.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,255 @@
+/*
+ * 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.agent.internal;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.internal.AgentInformationTypeAdapter.AgentInformationUpdateTypeAdapter;
+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.storage.core.AgentId;
+import com.redhat.thermostat.storage.model.AgentInformation;
+
+public class AgentInfoDAOImpl implements AgentInfoDAO {
+
+    private static final Logger logger = LoggingUtils.getLogger(AgentInfoDAOImpl.class);
+    
+    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
+    private static final String GATEWAY_PATH = "/agent-config/systems/*/agents/";
+    private static final String CONTENT_TYPE = "application/json";
+    
+    private final HttpHelper httpHelper;
+    private final JsonHelper jsonHelper;
+
+    public AgentInfoDAOImpl() throws Exception {
+        this(new HttpHelper(new HttpClient()), new JsonHelper(new AgentInformationTypeAdapter(),
+                                                              new AgentInformationUpdateTypeAdapter()));
+    }
+
+    AgentInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
+        this.httpHelper = httpHelper;
+        this.jsonHelper = jsonHelper;
+        
+        this.httpHelper.startClient();
+    }
+
+    @Override
+    public List<AgentInformation> getAllAgentInformation() {
+        return Collections.emptyList(); // TODO Remove once Agent Id completer is removed
+    }
+
+    @Override
+    public AgentInformation getAgentInformation(final AgentId agentId) {
+        return null; // TODO Remove once VM Id completer is removed
+    }
+
+    @Override
+    public Set<AgentId> getAgentIds() {
+        return Collections.emptySet(); // TODO Remove once VM Id completer is removed
+    }
+
+    @Override
+    public void addAgentInformation(final AgentInformation agentInfo) {
+        try {
+            // Encode as JSON and send as POST request
+            String json = jsonHelper.toJson(Arrays.asList(agentInfo));
+            StringContentProvider provider = httpHelper.createContentProvider(json);
+            
+            String url = getURL(agentInfo.getAgentId());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.POST);
+            httpRequest.content(provider, CONTENT_TYPE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to send agent information to web gateway", e);
+        }
+    }
+
+    @Override
+    public void removeAgentInformation(final AgentInformation agentInfo) {
+        try {
+            // Delete AgentInformation with matching Agent ID
+            String url = getURL(agentInfo.getAgentId());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.DELETE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to delete agent information from web gateway", e);
+        }
+    }
+
+    @Override
+    public void updateAgentInformation(final AgentInformation agentInfo) {
+        try {
+            // Encode as JSON and send as PUT request
+            AgentInformationUpdate update = new AgentInformationUpdate(agentInfo);
+            String json = jsonHelper.toJson(update);
+            StringContentProvider provider = httpHelper.createContentProvider(json);
+            
+            String url = getURL(agentInfo.getAgentId());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.PUT);
+            httpRequest.content(provider, CONTENT_TYPE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to send agent information update to web gateway", e);
+        }
+    }
+
+    private void sendRequest(Request httpRequest)
+            throws InterruptedException, TimeoutException, ExecutionException, IOException {
+        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());
+        }
+    }
+    
+    private String getURL(String agentId) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(GATEWAY_URL);
+        builder.append(GATEWAY_PATH);
+        builder.append(agentId);
+        return builder.toString();
+    }
+    
+    static class AgentInformationUpdate {
+        
+        private final AgentInformation info;
+        
+        AgentInformationUpdate(AgentInformation info) {
+            this.info = info;
+        }
+        
+        AgentInformation getInfo() {
+            return info;
+        }
+        
+    }
+    
+    // For testing purposes
+    static class JsonHelper {
+        
+        private final AgentInformationTypeAdapter typeAdapter;
+        private final AgentInformationUpdateTypeAdapter updateTypeAdapter;
+        
+        public JsonHelper(AgentInformationTypeAdapter typeAdapter, AgentInformationUpdateTypeAdapter updateTypeAdapter) {
+            this.typeAdapter = typeAdapter;
+            this.updateTypeAdapter = updateTypeAdapter;
+        }
+        
+        String toJson(List<AgentInformation> infos) throws IOException {
+            return typeAdapter.toJson(infos);
+        }
+        
+        String toJson(AgentInformationUpdate update) throws IOException {
+            return updateTypeAdapter.toJson(update);
+        }
+        
+    }
+    
+    // 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;
+        }
+        
+    }
+    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/AgentInformationTypeAdapter.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,132 @@
+/*
+ * 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.agent.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.agent.internal.AgentInfoDAOImpl.AgentInformationUpdate;
+import com.redhat.thermostat.storage.model.AgentInformation;
+
+public class AgentInformationTypeAdapter extends TypeAdapter<List<AgentInformation>> {
+    
+    private static final String AGENT_ID = "agentId";
+    private static final String START_TIME = "startTime";
+    private static final String STOP_TIME = "stopTime";
+    private static final String ALIVE = "alive";
+    private static final String CONFIG_LISTEN_ADDRESS = "configListenAddress";
+    private static final String TYPE_LONG = "$numberLong";
+    
+    @Override
+    public void write(JsonWriter out, List<AgentInformation> value) throws IOException {
+        // Request is an array of AgentInformation objects
+        out.beginArray();
+        
+        for (AgentInformation info : value) {
+            writeAgentInformation(out, info);
+        }
+        
+        out.endArray();
+    }
+
+    private void writeAgentInformation(JsonWriter out, AgentInformation info) throws IOException {
+        out.beginObject();
+        
+        // Write each field of AgentInformation as part of a JSON object
+        out.name(AGENT_ID);
+        out.value(info.getAgentId());
+        out.name(START_TIME);
+        writeLong(out, info.getStartTime());
+        out.name(STOP_TIME);
+        writeLong(out, info.getStopTime());
+        out.name(ALIVE);
+        out.value(info.isAlive());
+        out.name(CONFIG_LISTEN_ADDRESS);
+        out.value(info.getConfigListenAddress());
+        
+        out.endObject();
+    }
+
+    private static void writeLong(JsonWriter out, long value) throws IOException {
+        // Write MongoDB representation of a Long
+        out.beginObject();
+        out.name(TYPE_LONG);
+        out.value(String.valueOf(value));
+        out.endObject();
+    }
+    
+    @Override
+    public List<AgentInformation> read(JsonReader in) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+    
+    static class AgentInformationUpdateTypeAdapter extends TypeAdapter<AgentInformationUpdate> {
+        
+        private static final String SET = "set";
+
+        @Override
+        public void write(JsonWriter out, AgentInformationUpdate value) throws IOException {
+            // List fields to update as part of a JSON object with name "set"
+            out.beginObject();
+            out.name(SET);
+            
+            AgentInformation info = value.getInfo();
+            out.beginObject();
+            out.name(START_TIME);
+            writeLong(out, info.getStartTime());
+            out.name(STOP_TIME);
+            writeLong(out, info.getStopTime());
+            out.name(ALIVE);
+            out.value(info.isAlive());
+            out.name(CONFIG_LISTEN_ADDRESS);
+            out.value(info.getConfigListenAddress());
+            out.endObject();
+            
+            out.endObject();
+        }
+
+        @Override
+        public AgentInformationUpdate read(JsonReader in) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+        
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/BackendInfoDAOImpl.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,214 @@
+/*
+ * 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.agent.internal;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+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 com.redhat.thermostat.agent.dao.BackendInfoDAO;
+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.storage.model.BackendInformation;
+
+public class BackendInfoDAOImpl implements BackendInfoDAO {
+    
+    private static final Logger logger = LoggingUtils.getLogger(BackendInfoDAOImpl.class);
+    
+    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
+    private static final String GATEWAY_PATH = "/backend-info/systems/*/agents/";
+    private static final String CONTENT_TYPE = "application/json";
+    private static final String GATEWAY_QUERY = "?q=";
+    private static final String DELETE_QUERY_PARAM = "name==";
+
+    private final HttpHelper httpHelper;
+    private final JsonHelper jsonHelper;
+    
+    public BackendInfoDAOImpl() throws Exception {
+        this(new HttpHelper(new HttpClient()), new JsonHelper(new BackendInformationTypeAdapter()));
+    }
+
+    BackendInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
+        this.httpHelper = httpHelper;
+        this.jsonHelper = jsonHelper;
+        
+        this.httpHelper.startClient();
+    }
+
+    @Override
+    public void addBackendInformation(final BackendInformation info) {
+        try {
+            // Encode as JSON and send as POST request
+            String json = jsonHelper.toJson(Arrays.asList(info));
+            StringContentProvider provider = httpHelper.createContentProvider(json);
+            
+            String url = getAddURL(info.getAgentId());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.POST);
+            httpRequest.content(provider, CONTENT_TYPE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to send backend information to web gateway", e);
+        }
+    }
+
+    @Override
+    public void removeBackendInformation(final BackendInformation info) {
+        try {
+            // Delete BackendInformation with matching name
+            String url = getRemoveURL(info.getAgentId(), info.getName());
+            Request httpRequest = httpHelper.newRequest(url);
+            httpRequest.method(HttpMethod.DELETE);
+            sendRequest(httpRequest);
+        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
+           logger.log(Level.WARNING, "Failed to delete backend information from web gateway", e);
+        }
+    }
+
+    private void sendRequest(Request httpRequest)
+            throws InterruptedException, TimeoutException, ExecutionException, IOException {
+        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());
+        }
+    }
+
+    private String getAddURL(String agentId) {
+        return buildURL(agentId).toString();
+    }
+    
+    private String getRemoveURL(String agentId, String backendName) throws UnsupportedEncodingException {
+        StringBuilder builder = buildURL(agentId);
+        builder.append(GATEWAY_QUERY);
+        String query = DELETE_QUERY_PARAM.concat(backendName);
+        String encodedQuery = URLEncoder.encode(query, "UTF-8");
+        builder.append(encodedQuery);
+        return builder.toString();
+    }
+    
+    private StringBuilder buildURL(String agentId) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(GATEWAY_URL);
+        builder.append(GATEWAY_PATH);
+        builder.append(agentId);
+        return builder;
+    }
+    
+    // For testing purposes
+    static class JsonHelper {
+        
+        private final BackendInformationTypeAdapter typeAdapter;
+        
+        public JsonHelper(BackendInformationTypeAdapter typeAdapter) {
+            this.typeAdapter = typeAdapter;
+        }
+        
+        String toJson(List<BackendInformation> infos) throws IOException {
+            return typeAdapter.toJson(infos);
+        }
+        
+    }
+    
+    // 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;
+        }
+        
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/BackendInformationTypeAdapter.java	Tue Jun 20 13:00:11 2017 +0200
@@ -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.agent.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.storage.model.BackendInformation;
+
+public class BackendInformationTypeAdapter extends TypeAdapter<List<BackendInformation>> {
+    
+    private static final String AGENT_ID = "agentId";
+    private static final String NAME = "name";
+    private static final String DESCRIPTION = "description";
+    private static final String OBSERVE_NEW_JVM = "observeNewJvm";
+    private static final String PIDS = "pids";
+    private static final String ACTIVE = "active";
+    private static final String ORDER_VALUE = "orderValue";
+    
+    @Override
+    public void write(JsonWriter out, List<BackendInformation> value) throws IOException {
+        // Request is an array of BackendInformation objects
+        out.beginArray();
+        
+        for (BackendInformation info : value) {
+            writeBackendInformation(out, info);
+        }
+        
+        out.endArray();
+    }
+
+    private void writeBackendInformation(JsonWriter out, BackendInformation info) throws IOException {
+        out.beginObject();
+        
+        // Write each field of BackendInformation as part of a JSON object
+        out.name(AGENT_ID);
+        out.value(info.getAgentId());
+        out.name(NAME);
+        out.value(info.getName());
+        out.name(DESCRIPTION);
+        out.value(info.getDescription());
+        out.name(OBSERVE_NEW_JVM);
+        out.value(info.isObserveNewJvm());
+        out.name(PIDS);
+        writePidArray(out, info.getPids());
+        out.name(ACTIVE);
+        out.value(info.isActive());
+        out.name(ORDER_VALUE);
+        out.value(info.getOrderValue());
+        
+        out.endObject();
+    }
+
+    private void writePidArray(JsonWriter out, int[] pids) throws IOException {
+        // Output JSON array of PIDs
+        out.beginArray();
+        for (int pid : pids) {
+            out.value(pid);
+        }
+        out.endArray();
+    }
+
+    @Override
+    public List<BackendInformation> read(JsonReader in) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+    
+}
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -48,6 +48,8 @@
 
 import java.util.UUID;
 
+import com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.dao.BackendInfoDAO;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -59,8 +61,6 @@
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ThermostatExtensionRegistry;
 import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.BackendInformation;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/AgentInfoDAOTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,149 @@
+/*
+ * 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.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+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 com.redhat.thermostat.agent.dao.AgentInfoDAO;
+import com.redhat.thermostat.agent.internal.AgentInfoDAOImpl.AgentInformationUpdate;
+import com.redhat.thermostat.agent.internal.AgentInfoDAOImpl.HttpHelper;
+import com.redhat.thermostat.agent.internal.AgentInfoDAOImpl.JsonHelper;
+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 com.redhat.thermostat.storage.model.AgentInformation;
+
+public class AgentInfoDAOTest {
+
+    private static final String URL = "http://localhost:26000/api/v100/agent-config/systems/*/agents/1234";
+    private static final String SOME_JSON = "{\"some\" : \"json\"}";
+    private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}";
+    private static final String CONTENT_TYPE = "application/json";
+
+    private AgentInformation info;
+    private JsonHelper jsonHelper;
+    private HttpHelper httpHelper;
+    private StringContentProvider contentProvider;
+    private Request request;
+    private ContentResponse response;
+
+    @Before
+    public void setUp() throws Exception {
+        info = new AgentInformation("1234");
+        info.setAlive(true);
+        info.setConfigListenAddress("foobar:666");
+        info.setStartTime(100);
+        info.setStopTime(10);
+        
+        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(AgentInformation.class))).thenReturn(SOME_JSON);
+        when(jsonHelper.toJson(any(AgentInformationUpdate.class))).thenReturn(SOME_OTHER_JSON);
+    }
+
+    @Test
+    public void verifyAddAgentInformation() throws Exception {
+        AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper);
+
+        dao.addAgentInformation(info);
+
+        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 verifyUpdateAgentInformation() throws Exception {
+        AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper);
+
+        dao.updateAgentInformation(info);
+
+        verify(httpHelper).newRequest(URL);
+        verify(request).method(HttpMethod.PUT);
+        
+        ArgumentCaptor<AgentInformationUpdate> updateCaptor = ArgumentCaptor.forClass(AgentInformationUpdate.class);
+        verify(jsonHelper).toJson(updateCaptor.capture());
+        AgentInformationUpdate update = updateCaptor.getValue();
+        assertEquals(info, update.getInfo());
+                
+        verify(httpHelper).createContentProvider(SOME_OTHER_JSON);
+        verify(request).content(contentProvider, CONTENT_TYPE);
+        verify(request).send();
+        verify(response).getStatus();
+    }
+
+    @Test
+    public void verifyRemoveAgentInformation() throws Exception {
+        AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper);
+
+        dao.removeAgentInformation(info);
+
+        verify(httpHelper).newRequest(URL);
+        verify(request).method(HttpMethod.DELETE);
+        verify(request).send();
+        verify(response).getStatus();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/AgentInformationTypeAdapterTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.redhat.thermostat.agent.internal.AgentInfoDAOImpl.AgentInformationUpdate;
+import com.redhat.thermostat.agent.internal.AgentInformationTypeAdapter.AgentInformationUpdateTypeAdapter;
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.model.AgentInformation;
+
+public class AgentInformationTypeAdapterTest {
+    
+    @Test
+    public void testWrite() throws Exception {
+        AgentInformationTypeAdapter adapter = new AgentInformationTypeAdapter();
+        final String expected = "[{\"agentId\":\"agent1\",\"startTime\":{\"$numberLong\":\"4000\"},"
+                + "\"stopTime\":{\"$numberLong\":\"6000\"},\"alive\":false,\"configListenAddress\":\"127.0.0.1:12000\"},"
+                + "{\"agentId\":\"agent2\",\"startTime\":{\"$numberLong\":\"5000\"},\"stopTime\":{\"$numberLong\":\"0\"},"
+                + "\"alive\":true,\"configListenAddress\":\"1.2.3.4:12000\"}]";
+        
+        AgentInformation first = createAgentInformation("agent1", 4000L, 6000L, false, "127.0.0.1:12000");
+        AgentInformation second = createAgentInformation("agent2", 5000L, 0L, true, "1.2.3.4:12000");
+        List<AgentInformation> infos = Arrays.asList(first, second);
+        
+        String json = adapter.toJson(infos);
+        assertEquals(expected, json);
+    }
+    
+    @Test
+    public void testUpdate() throws Exception {
+        AgentInformationUpdateTypeAdapter adapter = new AgentInformationUpdateTypeAdapter();
+        final String expected = "{\"set\":{\"startTime\":{\"$numberLong\":\"5000\"},"
+                + "\"stopTime\":{\"$numberLong\":\"7000\"},\"alive\":false,\"configListenAddress\":\"1.2.3.4:12000\"}}";
+        
+        AgentInformation info = createAgentInformation("agent2", 5000L, 7000L, false, "1.2.3.4:12000");
+        AgentInformationUpdate update = new AgentInformationUpdate(info);
+        
+        String json = adapter.toJson(update);
+        assertEquals(expected, json);
+    }
+    
+    private AgentInformation createAgentInformation(String agentId, long startTime, long stopTime, 
+            boolean alive, String configListenAddress) {
+        AgentInformation info = new AgentInformation(agentId);
+        info.setStartTime(startTime);
+        info.setStopTime(stopTime);
+        info.setAlive(alive);
+        info.setConfigListenAddress(configListenAddress);
+        return info;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/BackendInfoDAOTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,127 @@
+/*
+ * 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.agent.internal;
+
+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 com.redhat.thermostat.agent.dao.BackendInfoDAO;
+import com.redhat.thermostat.agent.internal.BackendInfoDAOImpl.JsonHelper;
+import com.redhat.thermostat.agent.internal.BackendInfoDAOImpl.HttpHelper;
+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 com.redhat.thermostat.storage.model.BackendInformation;
+
+public class BackendInfoDAOTest {
+    
+    private static final String URL = "http://localhost:26000/api/v100/backend-info/systems/*/agents/foo-agent1";
+    private static final String REMOVE_URL = URL + "?q=name%3D%3DTest+Backend";
+    private static final String SOME_JSON = "{\"some\" : \"json\"}";
+    private static final String CONTENT_TYPE = "application/json";
+
+    private BackendInformation backendInfo1;
+    private JsonHelper jsonHelper;
+    private HttpHelper httpHelper;
+    private StringContentProvider contentProvider;
+    private Request request;
+    private ContentResponse response;
+
+    @Before
+    public void setUp() throws Exception {
+        backendInfo1 = new BackendInformation("foo-agent1");
+
+        backendInfo1.setName("Test Backend");
+        backendInfo1.setDescription("description");
+        backendInfo1.setActive(true);
+        backendInfo1.setObserveNewJvm(true);
+        backendInfo1.setPids(new int[] { -1, 0, 1});
+        backendInfo1.setOrderValue(100);
+
+        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(BackendInformation.class))).thenReturn(SOME_JSON);
+    }
+
+    @Test
+    public void verifyAddBackendInformation() throws Exception {
+        BackendInfoDAO dao = new BackendInfoDAOImpl(httpHelper, jsonHelper);
+
+        dao.addBackendInformation(backendInfo1);
+        
+        verify(httpHelper).newRequest(URL);
+        verify(request).method(HttpMethod.POST);
+        verify(jsonHelper).toJson(eq(Arrays.asList(backendInfo1)));
+        verify(httpHelper).createContentProvider(SOME_JSON);
+        verify(request).content(contentProvider, CONTENT_TYPE);
+        verify(request).send();
+        verify(response).getStatus();
+    }
+
+    @Test
+    public void verifyRemoveBackendInformation() throws Exception {
+        BackendInfoDAO dao = new BackendInfoDAOImpl(httpHelper, jsonHelper);
+        
+        dao.removeBackendInformation(backendInfo1);
+        
+        verify(httpHelper).newRequest(REMOVE_URL);
+        verify(request).method(HttpMethod.DELETE);
+        verify(request).send();
+        verify(response).getStatus();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/BackendInformationTypeAdapterTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.agent.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.storage.model.BackendInformation;
+
+public class BackendInformationTypeAdapterTest {
+    
+    private BackendInformationTypeAdapter adapter;
+    
+    @Before
+    public void setup() {
+        adapter = new BackendInformationTypeAdapter();
+    }
+
+    @Test
+    public void testWrite() throws Exception {
+        final String expected = "[{\"agentId\":\"agent1\",\"name\":\"First Backend\",\"description\":\"Gathers something\","
+                + "\"observeNewJvm\":true,\"pids\":[8000,9000],\"active\":true,\"orderValue\":280},"
+                + "{\"agentId\":\"agent2\",\"name\":\"Second Backend\",\"description\":\"Gathers something else\","
+                + "\"observeNewJvm\":false,\"pids\":[],\"active\":false,\"orderValue\":200}]";
+        
+        BackendInformation first = createBackendInformation("agent1", "First Backend", "Gathers something", true, 
+                new int[] { 8000, 9000 }, true, 280);
+        BackendInformation second = createBackendInformation("agent2", "Second Backend", "Gathers something else", false, 
+                new int[0], false, 200);
+        List<BackendInformation> infos = Arrays.asList(first, second);
+        
+        String json = adapter.toJson(infos);
+        assertEquals(expected, json);
+    }
+    
+    private BackendInformation createBackendInformation(String agentId, String name, String desc, 
+            boolean observeNewJvm, int[] pids, boolean active, int orderValue) {
+        BackendInformation info = new BackendInformation(agentId);
+        info.setName(name);
+        info.setDescription(desc);
+        info.setObserveNewJvm(observeNewJvm);
+        info.setPids(pids);
+        info.setActive(active);
+        info.setOrderValue(orderValue);
+        return info;
+    }
+
+}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -45,7 +45,6 @@
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import org.junit.Before;
 import org.junit.Test;
@@ -172,16 +171,7 @@
                 eq(launcherDeps), actionCaptor.capture()).thenReturn(launcherDepsTracker);
 
         MultipleServiceTracker unusedTracker = mock(MultipleServiceTracker.class);
-        Class<?>[] vmIdCompleterDeps = new Class[] {
-                AgentInfoDAO.class
-        };
-        whenNew(MultipleServiceTracker.class).withParameterTypes(BundleContext.class, Class[].class, Action.class).withArguments(eq(context),
-                eq(vmIdCompleterDeps), actionCaptor.capture()).thenReturn(unusedTracker);
-        Class<?>[] agentIdCompleterDeps = new Class[] {
-                AgentInfoDAO.class
-        };
-        whenNew(MultipleServiceTracker.class).withParameterTypes(BundleContext.class, Class[].class, Action.class).withArguments(eq(context),
-                eq(agentIdCompleterDeps), actionCaptor.capture()).thenReturn(unusedTracker);
+
         Class<?>[] helpCommandDeps = new Class[] {
                 CommandInfoSource.class,
                 CommandGroupMetadataSource.class
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -76,10 +76,8 @@
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.ExitStatus;
 import com.redhat.thermostat.common.Version;
-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.CommandException;
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.internal.test.TestCommandContextFactory;
 import com.redhat.thermostat.common.internal.test.TestTimerFactory;
@@ -88,7 +86,6 @@
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.launcher.internal.DisallowSystemExitSecurityManager.ExitException;
 import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
 public class LauncherImplTest {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +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.storage.dao;
-
-import java.util.List;
-import java.util.Set;
-
-import com.redhat.thermostat.annotations.Service;
-import com.redhat.thermostat.storage.core.AgentId;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-/**
- * Access information about agents that agents publish to storage.
- */
-@Service
-public interface AgentInfoDAO {
-    
-    /**
-     * Get information about all known agents.
-     *
-     * @return a {@link List} of {@link AgentInformation} for all agents
-     * who have published their information. Will be empty if there is no
-     * information.
-     */
-    List<AgentInformation> getAllAgentInformation();
-
-    /**
-     * Get information about a specific agent.
-     *
-     * @return a {@link AgentInformation} describing information about the agent
-     * indicated by {@code agentId}. {@code null} if no information about the
-     * agent could be located.
-     */
-
-    AgentInformation getAgentInformation(AgentId agentId);
-
-    /**
-     *
-     * @return A set of AgentIds, which may be empty.
-     */
-    Set<AgentId> getAgentIds();
-
-    /**
-     * Publish information about agent into the storage.
-     */
-    void addAgentInformation(AgentInformation agentInfo);
-
-    /**
-     * Update information about an existing agent. No changes will be performed
-     * if there is no matching agent.
-     */
-    void updateAgentInformation(AgentInformation agentInfo);
-
-    /**
-     * Remove information about an agent that was published to storage.
-     */
-    void removeAgentInformation(AgentInformation agentInfo);
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/BackendInfoDAO.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.storage.dao;
-
-import com.redhat.thermostat.annotations.Service;
-import com.redhat.thermostat.storage.model.BackendInformation;
-
-@Service
-public interface BackendInfoDAO {
-
-    void addBackendInformation(BackendInformation info);
-
-    void removeBackendInformation(BackendInformation info);
-
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java	Tue Jun 20 13:00:11 2017 +0200
@@ -45,11 +45,7 @@
 import org.osgi.framework.ServiceRegistration;
 
 import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl;
-import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl;
 import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl;
 
 public class Activator implements BundleActivator {
@@ -70,14 +66,6 @@
         final WriterID writerID = new WriterIDImpl(WRITER_UUID);
         ServiceRegistration<?> reg = context.registerService(WriterID.class, writerID, null);
         regs.add(reg);
-        
-        AgentInfoDAO agentInfoDao = new AgentInfoDAOImpl();
-        reg = context.registerService(AgentInfoDAO.class.getName(), agentInfoDao, null);
-        regs.add(reg);
-
-        BackendInfoDAO backendInfoDao = new BackendInfoDAOImpl();
-        reg = context.registerService(BackendInfoDAO.class.getName(), backendInfoDao, null);
-        regs.add(reg);
 
         NetworkInterfaceInfoDAO networkInfoDao = new NetworkInterfaceInfoDAOImpl();
         reg = context.registerService(NetworkInterfaceInfoDAO.class.getName(), networkInfoDao, null);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +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.storage.internal.dao;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-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.storage.core.AgentId;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.AgentInformationTypeAdapter.AgentInformationUpdateTypeAdapter;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class AgentInfoDAOImpl implements AgentInfoDAO {
-
-    private static final Logger logger = LoggingUtils.getLogger(AgentInfoDAOImpl.class);
-    
-    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
-    private static final String GATEWAY_PATH = "/agent-config/systems/*/agents/";
-    private static final String CONTENT_TYPE = "application/json";
-    
-    private final HttpHelper httpHelper;
-    private final JsonHelper jsonHelper;
-
-    public AgentInfoDAOImpl() throws Exception {
-        this(new HttpHelper(new HttpClient()), new JsonHelper(new AgentInformationTypeAdapter(), 
-                new AgentInformationUpdateTypeAdapter()));
-    }
-
-    AgentInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
-        this.httpHelper = httpHelper;
-        this.jsonHelper = jsonHelper;
-        
-        this.httpHelper.startClient();
-    }
-
-    @Override
-    public List<AgentInformation> getAllAgentInformation() {
-        return Collections.emptyList(); // TODO Remove once Agent Id completer is removed
-    }
-
-    @Override
-    public AgentInformation getAgentInformation(final AgentId agentId) {
-        return null; // TODO Remove once VM Id completer is removed
-    }
-
-    @Override
-    public Set<AgentId> getAgentIds() {
-        return Collections.emptySet(); // TODO Remove once VM Id completer is removed
-    }
-
-    @Override
-    public void addAgentInformation(final AgentInformation agentInfo) {
-        try {
-            // Encode as JSON and send as POST request
-            String json = jsonHelper.toJson(Arrays.asList(agentInfo));
-            StringContentProvider provider = httpHelper.createContentProvider(json);
-            
-            String url = getURL(agentInfo.getAgentId());
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.POST);
-            httpRequest.content(provider, CONTENT_TYPE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to send agent information to web gateway", e);
-        }
-    }
-
-    @Override
-    public void removeAgentInformation(final AgentInformation agentInfo) {
-        try {
-            // Delete AgentInformation with matching Agent ID
-            String url = getURL(agentInfo.getAgentId());
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.DELETE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to delete agent information from web gateway", e);
-        }
-    }
-
-    @Override
-    public void updateAgentInformation(final AgentInformation agentInfo) {
-        try {
-            // Encode as JSON and send as PUT request
-            AgentInformationUpdate update = new AgentInformationUpdate(agentInfo);
-            String json = jsonHelper.toJson(update);
-            StringContentProvider provider = httpHelper.createContentProvider(json);
-            
-            String url = getURL(agentInfo.getAgentId());
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.PUT);
-            httpRequest.content(provider, CONTENT_TYPE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to send agent information update to web gateway", e);
-        }
-    }
-
-    private void sendRequest(Request httpRequest)
-            throws InterruptedException, TimeoutException, ExecutionException, IOException {
-        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());
-        }
-    }
-    
-    private String getURL(String agentId) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(GATEWAY_URL);
-        builder.append(GATEWAY_PATH);
-        builder.append(agentId);
-        return builder.toString();
-    }
-    
-    static class AgentInformationUpdate {
-        
-        private final AgentInformation info;
-        
-        AgentInformationUpdate(AgentInformation info) {
-            this.info = info;
-        }
-        
-        AgentInformation getInfo() {
-            return info;
-        }
-        
-    }
-    
-    // For testing purposes
-    static class JsonHelper {
-        
-        private final AgentInformationTypeAdapter typeAdapter;
-        private final AgentInformationUpdateTypeAdapter updateTypeAdapter;
-        
-        public JsonHelper(AgentInformationTypeAdapter typeAdapter, AgentInformationUpdateTypeAdapter updateTypeAdapter) {
-            this.typeAdapter = typeAdapter;
-            this.updateTypeAdapter = updateTypeAdapter;
-        }
-        
-        String toJson(List<AgentInformation> infos) throws IOException {
-            return typeAdapter.toJson(infos);
-        }
-        
-        String toJson(AgentInformationUpdate update) throws IOException {
-            return updateTypeAdapter.toJson(update);
-        }
-        
-    }
-    
-    // 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/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapter.java	Mon Jun 19 20:10:51 2017 +0200
+++ /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.storage.internal.dao;
-
-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.storage.internal.dao.AgentInfoDAOImpl.AgentInformationUpdate;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class AgentInformationTypeAdapter extends TypeAdapter<List<AgentInformation>> {
-    
-    private static final String AGENT_ID = "agentId";
-    private static final String START_TIME = "startTime";
-    private static final String STOP_TIME = "stopTime";
-    private static final String ALIVE = "alive";
-    private static final String CONFIG_LISTEN_ADDRESS = "configListenAddress";
-    private static final String TYPE_LONG = "$numberLong";
-    
-    @Override
-    public void write(JsonWriter out, List<AgentInformation> value) throws IOException {
-        // Request is an array of AgentInformation objects
-        out.beginArray();
-        
-        for (AgentInformation info : value) {
-            writeAgentInformation(out, info);
-        }
-        
-        out.endArray();
-    }
-
-    private void writeAgentInformation(JsonWriter out, AgentInformation info) throws IOException {
-        out.beginObject();
-        
-        // Write each field of AgentInformation as part of a JSON object
-        out.name(AGENT_ID);
-        out.value(info.getAgentId());
-        out.name(START_TIME);
-        writeLong(out, info.getStartTime());
-        out.name(STOP_TIME);
-        writeLong(out, info.getStopTime());
-        out.name(ALIVE);
-        out.value(info.isAlive());
-        out.name(CONFIG_LISTEN_ADDRESS);
-        out.value(info.getConfigListenAddress());
-        
-        out.endObject();
-    }
-
-    private static void writeLong(JsonWriter out, long value) throws IOException {
-        // Write MongoDB representation of a Long
-        out.beginObject();
-        out.name(TYPE_LONG);
-        out.value(String.valueOf(value));
-        out.endObject();
-    }
-    
-    @Override
-    public List<AgentInformation> read(JsonReader in) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-    
-    static class AgentInformationUpdateTypeAdapter extends TypeAdapter<AgentInformationUpdate> {
-        
-        private static final String SET = "set";
-
-        @Override
-        public void write(JsonWriter out, AgentInformationUpdate value) throws IOException {
-            // List fields to update as part of a JSON object with name "set"
-            out.beginObject();
-            out.name(SET);
-            
-            AgentInformation info = value.getInfo();
-            out.beginObject();
-            out.name(START_TIME);
-            writeLong(out, info.getStartTime());
-            out.name(STOP_TIME);
-            writeLong(out, info.getStopTime());
-            out.name(ALIVE);
-            out.value(info.isAlive());
-            out.name(CONFIG_LISTEN_ADDRESS);
-            out.value(info.getConfigListenAddress());
-            out.endObject();
-            
-            out.endObject();
-        }
-
-        @Override
-        public AgentInformationUpdate read(JsonReader in) throws IOException {
-            throw new UnsupportedOperationException();
-        }
-        
-    }
-    
-}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +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.storage.internal.dao;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URLEncoder;
-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.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.storage.dao.BackendInfoDAO;
-import com.redhat.thermostat.storage.model.BackendInformation;
-
-public class BackendInfoDAOImpl implements BackendInfoDAO {
-    
-    private static final Logger logger = LoggingUtils.getLogger(BackendInfoDAOImpl.class);
-    
-    private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable
-    private static final String GATEWAY_PATH = "/backend-info/systems/*/agents/";
-    private static final String CONTENT_TYPE = "application/json";
-    private static final String GATEWAY_QUERY = "?q=";
-    private static final String DELETE_QUERY_PARAM = "name==";
-
-    private final HttpHelper httpHelper;
-    private final JsonHelper jsonHelper;
-    
-    public BackendInfoDAOImpl() throws Exception {
-        this(new HttpHelper(new HttpClient()), new JsonHelper(new BackendInformationTypeAdapter()));
-    }
-
-    BackendInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
-        this.httpHelper = httpHelper;
-        this.jsonHelper = jsonHelper;
-        
-        this.httpHelper.startClient();
-    }
-
-    @Override
-    public void addBackendInformation(final BackendInformation info) {
-        try {
-            // Encode as JSON and send as POST request
-            String json = jsonHelper.toJson(Arrays.asList(info));
-            StringContentProvider provider = httpHelper.createContentProvider(json);
-            
-            String url = getAddURL(info.getAgentId());
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.POST);
-            httpRequest.content(provider, CONTENT_TYPE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to send backend information to web gateway", e);
-        }
-    }
-
-    @Override
-    public void removeBackendInformation(final BackendInformation info) {
-        try {
-            // Delete BackendInformation with matching name
-            String url = getRemoveURL(info.getAgentId(), info.getName());
-            Request httpRequest = httpHelper.newRequest(url);
-            httpRequest.method(HttpMethod.DELETE);
-            sendRequest(httpRequest);
-        } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
-           logger.log(Level.WARNING, "Failed to delete backend information from web gateway", e);
-        }
-    }
-
-    private void sendRequest(Request httpRequest)
-            throws InterruptedException, TimeoutException, ExecutionException, IOException {
-        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());
-        }
-    }
-
-    private String getAddURL(String agentId) {
-        return buildURL(agentId).toString();
-    }
-    
-    private String getRemoveURL(String agentId, String backendName) throws UnsupportedEncodingException {
-        StringBuilder builder = buildURL(agentId);
-        builder.append(GATEWAY_QUERY);
-        String query = DELETE_QUERY_PARAM.concat(backendName);
-        String encodedQuery = URLEncoder.encode(query, "UTF-8");
-        builder.append(encodedQuery);
-        return builder.toString();
-    }
-    
-    private StringBuilder buildURL(String agentId) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(GATEWAY_URL);
-        builder.append(GATEWAY_PATH);
-        builder.append(agentId);
-        return builder;
-    }
-    
-    // For testing purposes
-    static class JsonHelper {
-        
-        private final BackendInformationTypeAdapter typeAdapter;
-        
-        public JsonHelper(BackendInformationTypeAdapter typeAdapter) {
-            this.typeAdapter = typeAdapter;
-        }
-        
-        String toJson(List<BackendInformation> infos) throws IOException {
-            return typeAdapter.toJson(infos);
-        }
-        
-    }
-    
-    // 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/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapter.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +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.storage.internal.dao;
-
-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.storage.model.BackendInformation;
-
-public class BackendInformationTypeAdapter extends TypeAdapter<List<BackendInformation>> {
-    
-    private static final String AGENT_ID = "agentId";
-    private static final String NAME = "name";
-    private static final String DESCRIPTION = "description";
-    private static final String OBSERVE_NEW_JVM = "observeNewJvm";
-    private static final String PIDS = "pids";
-    private static final String ACTIVE = "active";
-    private static final String ORDER_VALUE = "orderValue";
-    
-    @Override
-    public void write(JsonWriter out, List<BackendInformation> value) throws IOException {
-        // Request is an array of BackendInformation objects
-        out.beginArray();
-        
-        for (BackendInformation info : value) {
-            writeBackendInformation(out, info);
-        }
-        
-        out.endArray();
-    }
-
-    private void writeBackendInformation(JsonWriter out, BackendInformation info) throws IOException {
-        out.beginObject();
-        
-        // Write each field of BackendInformation as part of a JSON object
-        out.name(AGENT_ID);
-        out.value(info.getAgentId());
-        out.name(NAME);
-        out.value(info.getName());
-        out.name(DESCRIPTION);
-        out.value(info.getDescription());
-        out.name(OBSERVE_NEW_JVM);
-        out.value(info.isObserveNewJvm());
-        out.name(PIDS);
-        writePidArray(out, info.getPids());
-        out.name(ACTIVE);
-        out.value(info.isActive());
-        out.name(ORDER_VALUE);
-        out.value(info.getOrderValue());
-        
-        out.endObject();
-    }
-
-    private void writePidArray(JsonWriter out, int[] pids) throws IOException {
-        // Output JSON array of PIDs
-        out.beginArray();
-        for (int pid : pids) {
-            out.value(pid);
-        }
-        out.endArray();
-    }
-
-    @Override
-    public List<BackendInformation> read(JsonReader in) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-    
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java	Tue Jun 20 13:00:11 2017 +0200
@@ -48,11 +48,7 @@
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.storage.core.WriterID;
-import com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl;
-import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl;
 import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
@@ -67,8 +63,6 @@
 
         assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
 
         activator.stop(context);
 
@@ -87,8 +81,6 @@
         activator.stop(context);
         
         assertFalse(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertFalse(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
-        assertFalse(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
         assertFalse(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
         
         assertEquals(0, context.getServiceListeners().size());
@@ -110,8 +102,6 @@
         activator.start(context);
 
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
 
         activator.stop(context);
@@ -122,8 +112,6 @@
         activator.start(context);
 
         assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class));
-        assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class));
         assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
 
         activator.stop(context);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +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.storage.internal.dao;
-
-import static org.junit.Assert.assertEquals;
-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 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 com.redhat.thermostat.storage.dao.AgentInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.AgentInformationUpdate;
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.HttpHelper;
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.JsonHelper;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class AgentInfoDAOTest {
-
-    private static final String URL = "http://localhost:26000/api/v100/agent-config/systems/*/agents/1234";
-    private static final String SOME_JSON = "{\"some\" : \"json\"}";
-    private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}";
-    private static final String CONTENT_TYPE = "application/json";
-
-    private AgentInformation info;
-    private JsonHelper jsonHelper;
-    private HttpHelper httpHelper;
-    private StringContentProvider contentProvider;
-    private Request request;
-    private ContentResponse response;
-
-    @Before
-    public void setUp() throws Exception {
-        info = new AgentInformation("1234");
-        info.setAlive(true);
-        info.setConfigListenAddress("foobar:666");
-        info.setStartTime(100);
-        info.setStopTime(10);
-        
-        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(AgentInformation.class))).thenReturn(SOME_JSON);
-        when(jsonHelper.toJson(any(AgentInformationUpdate.class))).thenReturn(SOME_OTHER_JSON);
-    }
-
-    @Test
-    public void verifyAddAgentInformation() throws Exception {
-        AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper);
-
-        dao.addAgentInformation(info);
-
-        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 verifyUpdateAgentInformation() throws Exception {
-        AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper);
-
-        dao.updateAgentInformation(info);
-
-        verify(httpHelper).newRequest(URL);
-        verify(request).method(HttpMethod.PUT);
-        
-        ArgumentCaptor<AgentInformationUpdate> updateCaptor = ArgumentCaptor.forClass(AgentInformationUpdate.class);
-        verify(jsonHelper).toJson(updateCaptor.capture());
-        AgentInformationUpdate update = updateCaptor.getValue();
-        assertEquals(info, update.getInfo());
-                
-        verify(httpHelper).createContentProvider(SOME_OTHER_JSON);
-        verify(request).content(contentProvider, CONTENT_TYPE);
-        verify(request).send();
-        verify(response).getStatus();
-    }
-
-    @Test
-    public void verifyRemoveAgentInformation() throws Exception {
-        AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper);
-
-        dao.removeAgentInformation(info);
-
-        verify(httpHelper).newRequest(URL);
-        verify(request).method(HttpMethod.DELETE);
-        verify(request).send();
-        verify(response).getStatus();
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapterTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ /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.storage.internal.dao;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.AgentInformationUpdate;
-import com.redhat.thermostat.storage.internal.dao.AgentInformationTypeAdapter.AgentInformationUpdateTypeAdapter;
-import com.redhat.thermostat.storage.model.AgentInformation;
-
-public class AgentInformationTypeAdapterTest {
-    
-    @Test
-    public void testWrite() throws Exception {
-        AgentInformationTypeAdapter adapter = new AgentInformationTypeAdapter();
-        final String expected = "[{\"agentId\":\"agent1\",\"startTime\":{\"$numberLong\":\"4000\"},"
-                + "\"stopTime\":{\"$numberLong\":\"6000\"},\"alive\":false,\"configListenAddress\":\"127.0.0.1:12000\"},"
-                + "{\"agentId\":\"agent2\",\"startTime\":{\"$numberLong\":\"5000\"},\"stopTime\":{\"$numberLong\":\"0\"},"
-                + "\"alive\":true,\"configListenAddress\":\"1.2.3.4:12000\"}]";
-        
-        AgentInformation first = createAgentInformation("agent1", 4000L, 6000L, false, "127.0.0.1:12000");
-        AgentInformation second = createAgentInformation("agent2", 5000L, 0L, true, "1.2.3.4:12000");
-        List<AgentInformation> infos = Arrays.asList(first, second);
-        
-        String json = adapter.toJson(infos);
-        assertEquals(expected, json);
-    }
-    
-    @Test
-    public void testUpdate() throws Exception {
-        AgentInformationUpdateTypeAdapter adapter = new AgentInformationUpdateTypeAdapter();
-        final String expected = "{\"set\":{\"startTime\":{\"$numberLong\":\"5000\"},"
-                + "\"stopTime\":{\"$numberLong\":\"7000\"},\"alive\":false,\"configListenAddress\":\"1.2.3.4:12000\"}}";
-        
-        AgentInformation info = createAgentInformation("agent2", 5000L, 7000L, false, "1.2.3.4:12000");
-        AgentInformationUpdate update = new AgentInformationUpdate(info);
-        
-        String json = adapter.toJson(update);
-        assertEquals(expected, json);
-    }
-    
-    private AgentInformation createAgentInformation(String agentId, long startTime, long stopTime, 
-            boolean alive, String configListenAddress) {
-        AgentInformation info = new AgentInformation(agentId);
-        info.setStartTime(startTime);
-        info.setStopTime(stopTime);
-        info.setAlive(alive);
-        info.setConfigListenAddress(configListenAddress);
-        return info;
-    }
-
-}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +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.storage.internal.dao;
-
-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 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 com.redhat.thermostat.storage.dao.BackendInfoDAO;
-import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl.HttpHelper;
-import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl.JsonHelper;
-import com.redhat.thermostat.storage.model.BackendInformation;
-
-public class BackendInfoDAOTest {
-    
-    private static final String URL = "http://localhost:26000/api/v100/backend-info/systems/*/agents/foo-agent1";
-    private static final String REMOVE_URL = URL + "?q=name%3D%3DTest+Backend";
-    private static final String SOME_JSON = "{\"some\" : \"json\"}";
-    private static final String CONTENT_TYPE = "application/json";
-
-    private BackendInformation backendInfo1;
-    private JsonHelper jsonHelper;
-    private HttpHelper httpHelper;
-    private StringContentProvider contentProvider;
-    private Request request;
-    private ContentResponse response;
-
-    @Before
-    public void setUp() throws Exception {
-        backendInfo1 = new BackendInformation("foo-agent1");
-
-        backendInfo1.setName("Test Backend");
-        backendInfo1.setDescription("description");
-        backendInfo1.setActive(true);
-        backendInfo1.setObserveNewJvm(true);
-        backendInfo1.setPids(new int[] { -1, 0, 1});
-        backendInfo1.setOrderValue(100);
-
-        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(BackendInformation.class))).thenReturn(SOME_JSON);
-    }
-
-    @Test
-    public void verifyAddBackendInformation() throws Exception {
-        BackendInfoDAO dao = new BackendInfoDAOImpl(httpHelper, jsonHelper);
-
-        dao.addBackendInformation(backendInfo1);
-        
-        verify(httpHelper).newRequest(URL);
-        verify(request).method(HttpMethod.POST);
-        verify(jsonHelper).toJson(eq(Arrays.asList(backendInfo1)));
-        verify(httpHelper).createContentProvider(SOME_JSON);
-        verify(request).content(contentProvider, CONTENT_TYPE);
-        verify(request).send();
-        verify(response).getStatus();
-    }
-
-    @Test
-    public void verifyRemoveBackendInformation() throws Exception {
-        BackendInfoDAO dao = new BackendInfoDAOImpl(httpHelper, jsonHelper);
-        
-        dao.removeBackendInformation(backendInfo1);
-        
-        verify(httpHelper).newRequest(REMOVE_URL);
-        verify(request).method(HttpMethod.DELETE);
-        verify(request).send();
-        verify(response).getStatus();
-    }
-
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapterTest.java	Mon Jun 19 20:10:51 2017 +0200
+++ /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.storage.internal.dao;
-
-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.storage.model.BackendInformation;
-
-public class BackendInformationTypeAdapterTest {
-    
-    private BackendInformationTypeAdapter adapter;
-    
-    @Before
-    public void setup() {
-        adapter = new BackendInformationTypeAdapter();
-    }
-
-    @Test
-    public void testWrite() throws Exception {
-        final String expected = "[{\"agentId\":\"agent1\",\"name\":\"First Backend\",\"description\":\"Gathers something\","
-                + "\"observeNewJvm\":true,\"pids\":[8000,9000],\"active\":true,\"orderValue\":280},"
-                + "{\"agentId\":\"agent2\",\"name\":\"Second Backend\",\"description\":\"Gathers something else\","
-                + "\"observeNewJvm\":false,\"pids\":[],\"active\":false,\"orderValue\":200}]";
-        
-        BackendInformation first = createBackendInformation("agent1", "First Backend", "Gathers something", true, 
-                new int[] { 8000, 9000 }, true, 280);
-        BackendInformation second = createBackendInformation("agent2", "Second Backend", "Gathers something else", false, 
-                new int[0], false, 200);
-        List<BackendInformation> infos = Arrays.asList(first, second);
-        
-        String json = adapter.toJson(infos);
-        assertEquals(expected, json);
-    }
-    
-    private BackendInformation createBackendInformation(String agentId, String name, String desc, 
-            boolean observeNewJvm, int[] pids, boolean active, int orderValue) {
-        BackendInformation info = new BackendInformation(agentId);
-        info.setName(name);
-        info.setDescription(desc);
-        info.setObserveNewJvm(observeNewJvm);
-        info.setPids(pids);
-        info.setActive(active);
-        info.setOrderValue(orderValue);
-        return info;
-    }
-
-}