changeset 2636:a21f33af2bfd

Update BackendInfoDAO to communicate with web gateway Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/022958.html
author Elliott Baron <ebaron@redhat.com>
date Fri, 05 May 2017 12:15:44 -0400
parents 543cd4a5912a
children 8781afc57d5e
files storage/core/src/main/java/com/redhat/thermostat/storage/dao/BackendInfoDAO.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/dao/BackendInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapterTest.java
diffstat 5 files changed, 390 insertions(+), 242 deletions(-) [+]
line wrap: on
line diff
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/BackendInfoDAO.java	Fri May 05 12:14:51 2017 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/dao/BackendInfoDAO.java	Fri May 05 12:15:44 2017 -0400
@@ -39,9 +39,7 @@
 import java.util.List;
 
 import com.redhat.thermostat.annotations.Service;
-import com.redhat.thermostat.storage.core.AgentId;
 import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.model.BackendInformation;
 
@@ -64,12 +62,6 @@
             PIDS_TO_MONITOR,
             ORDER_VALUE);
 
-    /** @deprecated use {@link #getBackendInformation(AgentId)} instead. */
-    @Deprecated
-    List<BackendInformation> getBackendInformation(HostRef host);
-
-    List<BackendInformation> getBackendInformation(AgentId agentId);
-
     void addBackendInformation(BackendInformation info);
 
     void removeBackendInformation(BackendInformation info);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Fri May 05 12:14:51 2017 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Fri May 05 12:15:44 2017 -0400
@@ -36,120 +36,178 @@
 
 package com.redhat.thermostat.storage.internal.dao;
 
-import java.util.ArrayList;
-import java.util.Collections;
+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.common.OrderedComparator;
+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.core.HostRef;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
-import com.redhat.thermostat.storage.dao.AbstractDaoStatement;
 import com.redhat.thermostat.storage.dao.BackendInfoDAO;
 import com.redhat.thermostat.storage.model.BackendInformation;
 
-public class BackendInfoDAOImpl extends AbstractDao implements BackendInfoDAO {
+public class BackendInfoDAOImpl implements BackendInfoDAO {
     
     private static final Logger logger = LoggingUtils.getLogger(BackendInfoDAOImpl.class);
-    static final String QUERY_BACKEND_INFO = "QUERY "
-            + CATEGORY.getName() + " WHERE '" 
-            + Key.AGENT_ID.getName() + "' = ?s";
-    // ADD backend-info SET \
-    //                   'agentId' = ?s , \
-    //                   'name' = ?s , \
-    //                   'description' = ?s , \
-    //                   'observeNewJvm' = ?b , \
-    //                   'pids' = ?i[ , \
-    //                   'active' = ?b , \
-    //                   'orderValue' = ?i
-    static final String DESC_ADD_BACKEND_INFO = "ADD " + CATEGORY.getName() + " SET " +
-            "'" + Key.AGENT_ID.getName() + "' = ?s , " +
-            "'" + BACKEND_NAME.getName() + "' = ?s , " +
-            "'" + BACKEND_DESCRIPTION.getName() + "' = ?s , " +
-            "'" + SHOULD_MONITOR_NEW_PROCESSES.getName() + "' = ?b , " +
-            "'" + PIDS_TO_MONITOR.getName() + "' = ?i[ , " +
-            "'" + IS_ACTIVE.getName() + "' = ?b , " +
-            "'" + ORDER_VALUE.getName() + "' = ?i";
-    // REMOVE backend-info WHERE 'name' = ?s
-    static final String DESC_REMOVE_BACKEND_INFO = "REMOVE " + CATEGORY.getName() +
-            " WHERE '" + BACKEND_NAME.getName() + "' = ?s";
+    
+    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 = BACKEND_NAME.getName() + "==";
 
-    private final Storage storage;
-
-    public BackendInfoDAOImpl(Storage storage) {
-        this.storage = storage;
-        storage.registerCategory(CATEGORY);
+    private final HttpHelper httpHelper;
+    private final JsonHelper jsonHelper;
+    
+    public BackendInfoDAOImpl() throws Exception {
+        this(new HttpHelper(new HttpClient()), new JsonHelper(new BackendInformationTypeAdapter()));
     }
 
-    @Override
-    public List<BackendInformation> getBackendInformation(final HostRef host) {
-        List<BackendInformation> result = executeQuery(
-                new AbstractDaoQuery<BackendInformation>(storage, CATEGORY, QUERY_BACKEND_INFO) {
-                    @Override
-                    public PreparedStatement<BackendInformation> customize(PreparedStatement<BackendInformation> preparedStatement) {
-                        preparedStatement.setString(0, host.getAgentId());
-                        return preparedStatement;
-                    }
-                }).asList();
-        List<BackendInformation> sorted = new ArrayList<>(result);
-        Collections.sort(sorted, new OrderedComparator<>());
-        return sorted;
-    }
-
-    @Override
-    public List<BackendInformation> getBackendInformation(final AgentId agentId) {
-        List<BackendInformation> result = executeQuery(
-                new AbstractDaoQuery<BackendInformation>(storage, CATEGORY, QUERY_BACKEND_INFO) {
-                    @Override
-                    public PreparedStatement<BackendInformation> customize(PreparedStatement<BackendInformation> preparedStatement) {
-                        preparedStatement.setString(0, agentId.get());
-                        return preparedStatement;
-                    }
-                }).asList();
-        List<BackendInformation> sorted = new ArrayList<>(result);
-        Collections.sort(sorted, new OrderedComparator<>());
-        return sorted;
+    BackendInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception {
+        this.httpHelper = httpHelper;
+        this.jsonHelper = jsonHelper;
+        
+        this.httpHelper.startClient();
     }
 
     @Override
     public void addBackendInformation(final BackendInformation info) {
-        executeStatement(
-                new AbstractDaoStatement<BackendInformation>(storage, CATEGORY, DESC_ADD_BACKEND_INFO) {
-                    @Override
-                    public PreparedStatement<BackendInformation> customize(PreparedStatement<BackendInformation> preparedStatement) {
-                        preparedStatement.setString(0, info.getAgentId());
-                        preparedStatement.setString(1, info.getName());
-                        preparedStatement.setString(2, info.getDescription());
-                        preparedStatement.setBoolean(3, info.isObserveNewJvm());
-                        preparedStatement.setIntList(4, info.getPids());
-                        preparedStatement.setBoolean(5, info.isActive());
-                        preparedStatement.setInt(6, info.getOrderValue());
-                        return preparedStatement;
-                    }
-                });
+        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) {
-        executeStatement(
-                new AbstractDaoStatement<BackendInformation>(storage, CATEGORY, DESC_REMOVE_BACKEND_INFO) {
-                    @Override
-                    public PreparedStatement<BackendInformation> customize(PreparedStatement<BackendInformation> preparedStatement) {
-                        preparedStatement.setString(0, info.getName());
-                        return preparedStatement;
-                    }
-                });
+        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());
+        }
     }
 
-    @Override
-    protected Logger getLogger() {
-        return logger;
+    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/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapter.java	Fri May 05 12:15:44 2017 -0400
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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/dao/BackendInfoDAOTest.java	Fri May 05 12:14:51 2017 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Fri May 05 12:15:44 2017 -0400
@@ -38,75 +38,70 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 
+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.core.AgentId;
 import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.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 BackendInformation backend1;
+    private JsonHelper jsonHelper;
+    private HttpHelper httpHelper;
+    private StringContentProvider contentProvider;
+    private Request request;
+    private ContentResponse response;
 
     @Before
-    public void setUp() {
-
+    public void setUp() throws Exception {
         backendInfo1 = new BackendInformation("foo-agent1");
 
-        backendInfo1.setName("backend-name");
+        backendInfo1.setName("Test Backend");
         backendInfo1.setDescription("description");
         backendInfo1.setActive(true);
         backendInfo1.setObserveNewJvm(true);
         backendInfo1.setPids(new int[] { -1, 0, 1});
         backendInfo1.setOrderValue(100);
 
-        backend1 = new BackendInformation("foo-agent2");
-        backend1.setName("backend-name");
-        backend1.setDescription("description");
-        backend1.setActive(true);
-        backend1.setObserveNewJvm(true);
-        backend1.setPids(new int[] { -1, 0, 1});
-        backend1.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 preparedQueryDescriptorsAreSane() {
-        String expectedBackendInfo = "QUERY backend-info WHERE 'agentId' = ?s";
-        assertEquals(expectedBackendInfo, BackendInfoDAOImpl.QUERY_BACKEND_INFO);
-        String addBackendInfo = "ADD backend-info SET " +
-                                        "'agentId' = ?s , " +
-                                        "'name' = ?s , " +
-                                        "'description' = ?s , " +
-                                        "'observeNewJvm' = ?b , " +
-                                        "'pids' = ?i[ , " +
-                                        "'active' = ?b , " +
-                                        "'orderValue' = ?i";
-        assertEquals(addBackendInfo, BackendInfoDAOImpl.DESC_ADD_BACKEND_INFO);
-    }
-
-    @Test
     public void verifyCategoryName() {
         Category<BackendInformation> c = BackendInfoDAO.CATEGORY;
         assertEquals("backend-info", c.getName());
@@ -126,120 +121,31 @@
         assertTrue(keys.contains(BackendInfoDAO.ORDER_VALUE));
     }
 
-    @SuppressWarnings("unchecked")
     @Test
-    public void verifyAddBackendInformation()
-            throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        PreparedStatement<BackendInformation> add = mock(PreparedStatement.class);
-        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add);
-
-        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
+    public void verifyAddBackendInformation() throws Exception {
+        BackendInfoDAO dao = new BackendInfoDAOImpl(httpHelper, jsonHelper);
 
         dao.addBackendInformation(backendInfo1);
         
-        @SuppressWarnings("rawtypes")
-        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
-        
-        verify(storage).prepareStatement(captor.capture());
-        StatementDescriptor<?> desc = captor.getValue();
-        assertEquals(BackendInfoDAOImpl.DESC_ADD_BACKEND_INFO, desc.getDescriptor());
-
-        verify(add).setString(0, backendInfo1.getAgentId());
-        verify(add).setString(1, backendInfo1.getName());
-        verify(add).setString(2, backendInfo1.getDescription());
-        verify(add).setBoolean(3, backendInfo1.isObserveNewJvm());
-        verify(add).setIntList(4, backendInfo1.getPids());
-        verify(add).setBoolean(5, backendInfo1.isActive());
-        verify(add).setInt(6, backendInfo1.getOrderValue());
-        verify(add).execute();
-        verifyNoMoreInteractions(add);
+        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 verifyGetBackendInformation() throws DescriptorParsingException, StatementExecutionException {
-        final String AGENT_ID = "agent-id";
-        HostRef agentref = mock(HostRef.class);
-        when(agentref.getAgentId()).thenReturn(AGENT_ID);
-
-        @SuppressWarnings("unchecked")
-        Cursor<BackendInformation> backendCursor = (Cursor<BackendInformation>) mock(Cursor.class);
-        when(backendCursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(backendCursor.next()).thenReturn(backend1).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<BackendInformation> stmt = (PreparedStatement<BackendInformation>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
-        when(stmt.executeQuery()).thenReturn(backendCursor);
-
-        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
-
-        List<BackendInformation> result = dao.getBackendInformation(agentref);
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(stmt).setString(0, AGENT_ID);
-        verify(stmt).executeQuery();
-        verifyNoMoreInteractions(stmt);
-
-        assertEquals(Arrays.asList(backendInfo1), result);
-    }
-
-    @Test
-    public void verifyGetBackendInformationWithAgentId() throws DescriptorParsingException, StatementExecutionException {
-        final String AGENT_ID = "agent-id";
-        AgentId agentId = new AgentId(AGENT_ID);
-
-        @SuppressWarnings("unchecked")
-        Cursor<BackendInformation> backendCursor = (Cursor<BackendInformation>) mock(Cursor.class);
-        when(backendCursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(backendCursor.next()).thenReturn(backend1).thenReturn(null);
-
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<BackendInformation> stmt = (PreparedStatement<BackendInformation>) mock(PreparedStatement.class);
-        when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt);
-        when(stmt.executeQuery()).thenReturn(backendCursor);
-
-        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
-
-        List<BackendInformation> result = dao.getBackendInformation(agentId);
-
-        verify(storage).prepareStatement(anyDescriptor());
-        verify(stmt).setString(0, AGENT_ID);
-        verify(stmt).executeQuery();
-        verifyNoMoreInteractions(stmt);
-
-        assertEquals(Arrays.asList(backendInfo1), result);
-    }
-
-    @SuppressWarnings("unchecked")
-    private StatementDescriptor<BackendInformation> anyDescriptor() {
-        return (StatementDescriptor<BackendInformation>) any(StatementDescriptor.class);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyRemoveBackendInformation()
-            throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        PreparedStatement<BackendInformation> remove = mock(PreparedStatement.class);
-        when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(remove);
+    public void verifyRemoveBackendInformation() throws Exception {
+        BackendInfoDAO dao = new BackendInfoDAOImpl(httpHelper, jsonHelper);
         
-        BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
-
         dao.removeBackendInformation(backendInfo1);
         
-        @SuppressWarnings("rawtypes")
-        ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class);
-        
-        verify(storage).prepareStatement(captor.capture());
-        StatementDescriptor<?> desc = captor.getValue();
-        assertEquals(BackendInfoDAOImpl.DESC_REMOVE_BACKEND_INFO, desc.getDescriptor());
-
-        verify(remove).setString(0, backendInfo1.getName());
-        verify(remove).execute();
-        verifyNoMoreInteractions(remove);
+        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/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInformationTypeAdapterTest.java	Fri May 05 12:15:44 2017 -0400
@@ -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.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;
+    }
+
+}