changeset 184:586afca62e7f

Add initial framework for metadata responses. Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-June/023574.html
author Chris Lessard <clessard@redhat.com>
date Tue, 20 Jun 2017 14:19:38 -0400
parents 30f6f82f9f6d
children 550361e046a6
files common/mongodb/pom.xml common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/executor/MongoDataResultContainer.java common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/executor/MongoExecutor.java common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataGenerator.java common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataResponseBuilder.java common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoResponseBuilder.java common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataGeneratorTest.java common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataResponseBuilderTest.java common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoResponseBuilderTest.java services/jvm-gc/src/main/java/com/redhat/thermostat/service/jvm/gc/JvmGcHttpHandler.java services/jvm-memory/src/main/java/com/redhat/thermostat/service/jvm/memory/JvmMemoryHttpHandler.java services/jvms/src/main/java/com/redhat/thermostat/service/jvms/mongo/MongoStorageHandler.java services/system-cpu/src/main/java/com/redhat/thermostat/service/cpuinfo/mongo/MongoStorageHandler.java services/system-memory/src/main/java/com/redhat/thermostat/service/systemmemory/mongo/MongoStorageHandler.java services/systems/src/main/java/com/redhat/thermostat/service/systems/mongo/MongoStorageHandler.java tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/gc/JvmGcServiceIntegrationTest.java tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/memory/JvmMemoryServiceIntegrationTest.java tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvms/JvmsServiceIntegrationTest.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/HttpTestUtil.java
diffstat 19 files changed, 1388 insertions(+), 431 deletions(-) [+]
line wrap: on
line diff
--- a/common/mongodb/pom.xml	Mon Jun 19 17:57:13 2017 +0200
+++ b/common/mongodb/pom.xml	Tue Jun 20 14:19:38 2017 -0400
@@ -85,6 +85,11 @@
             <version>${mockito-core.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.2.4</version>
+        </dependency>
     </dependencies>
 </project>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/executor/MongoDataResultContainer.java	Tue Jun 20 14:19:38 2017 -0400
@@ -0,0 +1,109 @@
+/*
+ * 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.gateway.common.mongodb.executor;
+
+import org.bson.Document;
+
+import com.mongodb.client.FindIterable;
+
+public class MongoDataResultContainer {
+
+    private long getReqCount;
+    private long postReqMatches;
+    private long postReqInsertions;
+    private long putReqMatches;
+    private long deleteReqMatches;
+    private int remainingNumQueryDocuments;
+    private FindIterable<Document> getReqQueryResult;
+
+    public void setGetReqCount(long getReqCount) {
+        this.getReqCount = getReqCount;
+    }
+
+    public void setQueryDataResult(FindIterable<Document> documents) {
+        getReqQueryResult = documents;
+    }
+
+    public FindIterable<Document> getQueryDataResult() {
+        return getReqQueryResult;
+    }
+
+    public void setPostReqInsertions(long postReqInsertions) {
+        this.postReqInsertions = postReqInsertions;
+    }
+
+    public void setPostReqMatches(long postReqUpdates) {
+        this.postReqMatches = postReqUpdates;
+    }
+
+    public void setPutReqMatches(long putReqUpdates) {
+        this.putReqMatches = putReqUpdates;
+    }
+
+    public void setDeleteReqMatches(long deleteReqMatches) {
+        this.deleteReqMatches = deleteReqMatches;
+    }
+
+    public void setRemainingNumQueryDocuments(int remainingNumQueryDocuments) {
+        this.remainingNumQueryDocuments = remainingNumQueryDocuments;
+    }
+
+    public long getGetReqCount() {
+        return this.getReqCount;
+    }
+
+    public long getPostReqInsertions() {
+        return postReqInsertions;
+    }
+
+    public long getPostReqMatches() {
+        return postReqMatches;
+    }
+
+    public long getPutReqMatches() {
+        return putReqMatches;
+    }
+
+    public long getDeleteReqMatches() {
+        return deleteReqMatches;
+    }
+
+    public int getRemainingNumQueryDocuments() {
+        return remainingNumQueryDocuments;
+    }
+
+}
\ No newline at end of file
--- a/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/executor/MongoExecutor.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/executor/MongoExecutor.java	Tue Jun 20 14:19:38 2017 -0400
@@ -55,17 +55,20 @@
 import com.mongodb.util.JSON;
 import com.redhat.thermostat.gateway.common.mongodb.filters.MongoRequestFilters;
 import com.redhat.thermostat.gateway.common.mongodb.filters.MongoSortFilters;
-import com.redhat.thermostat.gateway.common.mongodb.response.MongoResponseBuilder;
 
 public class MongoExecutor {
-    private final MongoResponseBuilder mongoResponseBuilder = new MongoResponseBuilder();
 
-    public String buildGetResponse(MongoCollection<Document> collection, Integer limit, Integer offset, String sort, String queries, String projections) {
+    public MongoDataResultContainer execGetRequest(MongoCollection<Document> collection, Integer limit,
+                                                   Integer offset, String sort, String queries, String projections) {
         FindIterable<Document> documents;
+        MongoDataResultContainer queryDataContainer = new MongoDataResultContainer();
+
         if (queries != null) {
             List<String> queriesList = Arrays.asList(queries.split(","));
             final Bson query = MongoRequestFilters.buildQueriesFilter(queriesList);
             documents = collection.find(query);
+            queryDataContainer.setGetReqCount(collection.count(query));
+            queryDataContainer.setRemainingNumQueryDocuments((int) (collection.count(query) - (limit + offset)));
         } else {
             documents = collection.find();
         }
@@ -79,12 +82,14 @@
 
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit).cursorType(CursorType.NonTailable);
+        queryDataContainer.setQueryDataResult(documents);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return queryDataContainer;
     }
 
-    public void buildPutResponse(MongoCollection<Document> collection, String body, String queries) {
+    public MongoDataResultContainer execPutRequest(MongoCollection<Document> collection, String body, String queries) {
         BasicDBObject inputObject = (BasicDBObject) JSON.parse(body);
+        MongoDataResultContainer metaDataContainer = new MongoDataResultContainer();
 
         final List<String> queriesList;
         if (queries != null) {
@@ -95,25 +100,40 @@
 
         BasicDBObject setObject = (BasicDBObject) inputObject.get("set");
         final Bson fields = new Document("$set", setObject);
+        final Bson bsonQueries = MongoRequestFilters.buildQueriesFilter(queriesList);
+        collection.updateMany(bsonQueries, fields);
 
-        collection.updateMany(MongoRequestFilters.buildQueriesFilter(queriesList), fields);
+        metaDataContainer.setPutReqMatches(collection.count(bsonQueries));
+
+        return metaDataContainer;
     }
 
-    public void buildDeleteResponse(MongoCollection<Document> collection, String queries) {
+    public MongoDataResultContainer execDeleteRequest(MongoCollection<Document> collection, String queries) {
         List<String> queriesList;
+        MongoDataResultContainer metaDataContainer = new MongoDataResultContainer();
         if (queries != null) {
             queriesList = Arrays.asList(queries.split(","));
-            collection.deleteMany(MongoRequestFilters.buildQueriesFilter(queriesList));
+            Bson bsonQueries = MongoRequestFilters.buildQueriesFilter(queriesList);
+            collection.deleteMany(bsonQueries);
 
+            metaDataContainer.setDeleteReqMatches(collection.count(bsonQueries));
+            return metaDataContainer;
         } else {
             collection.drop();
         }
+
+        return metaDataContainer;
     }
 
-    public void buildPost(MongoCollection<DBObject> collection, String body) {
+    public MongoDataResultContainer execPostRequest(MongoCollection<DBObject> collection, String body) {
+        MongoDataResultContainer metaDataContainer = new MongoDataResultContainer();
+
         if (body.length() > 0) {
             List<DBObject> inputList = (List<DBObject>) JSON.parse(body);
             collection.insertMany(inputList);
         }
+
+        return metaDataContainer;
     }
-}
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataGenerator.java	Tue Jun 20 14:19:38 2017 -0400
@@ -0,0 +1,108 @@
+/*
+ * 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.gateway.common.mongodb.response;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.redhat.thermostat.gateway.common.mongodb.executor.MongoDataResultContainer;
+
+public class MongoMetaDataGenerator {
+
+    private final Integer limit;
+    private final Integer offset;
+    private final String sort;
+    private final String queries;
+    private final String projections;
+    private final MongoDataResultContainer execResult;
+    private final HttpServletRequest requestInfo;
+    private final String baseURL;
+
+    public MongoMetaDataGenerator(Integer limit, Integer offset, String sort, String queries, String projections,
+                                  HttpServletRequest requestInfo, MongoDataResultContainer execResult) {
+        this.limit = limit;
+        this.offset = offset;
+        this.sort = sort;
+        this.queries = queries;
+        this.projections = projections;
+        this.execResult = execResult;
+        this.requestInfo = requestInfo;
+        this.baseURL = requestInfo.getRequestURL().toString();
+    }
+
+    public void setDocAndPayloadCount(MongoMetaDataResponseBuilder.MetaBuilder response) {
+        if (!"".equals(queries)) {
+            Integer docCount = (int) execResult.getGetReqCount();
+            Integer payloadCount = (limit > 1) ? 0 : docCount;
+            response.count(docCount).payloadCount(payloadCount);
+        }
+    }
+
+    public void setPrev(MongoMetaDataResponseBuilder.MetaBuilder response) {
+        if (!Integer.valueOf(0).equals(offset)) {
+            StringBuilder prev = new StringBuilder();
+            String[] arguments = requestInfo.getQueryString().split("&");
+            prev.append(baseURL).append("?").append(response.getQueryArgumentsNoOffsetLimit(arguments));
+
+            if (limit > 1) {
+                int newLim = (offset >= limit) ? limit : offset;
+                int newOff = (offset >= limit) ? (offset - limit) : 0;
+                prev.append("&").append("l=").append(newLim).append("&").append("o=").append(newOff);
+            } else {
+                prev.append("&").append("l=").append(offset);
+            }
+
+            response.prev(prev.toString());
+        }
+    }
+
+    public void setNext(MongoMetaDataResponseBuilder.MetaBuilder response) {
+        if (!"".equals(queries)) {
+            int remaining = execResult.getRemainingNumQueryDocuments();
+            if (!limit.equals(0) && remaining != 0) {
+                StringBuilder next = new StringBuilder();
+                int nextLimit = (remaining > limit) ? limit : remaining;
+                next.append(baseURL).append("?o=").append(offset + limit).append("&l=").append(nextLimit).append("&");
+
+                String[] arguments = requestInfo.getQueryString().split("&");
+                next.append(response.getQueryArgumentsNoOffsetLimit(arguments));
+
+                response.payloadCount(nextLimit).next(next.toString());
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataResponseBuilder.java	Tue Jun 20 14:19:38 2017 -0400
@@ -0,0 +1,151 @@
+/*
+ * 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.gateway.common.mongodb.response;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/*
+ *  Builds the appropriate metadata for the response after executing the request's MongoDB Query.
+ *
+ *  NOTE: Builder fields that aren't explicitly set - and therefore null - are omitted in the
+ *        serialized JSON.
+ */
+public class MongoMetaDataResponseBuilder {
+
+    private final transient Gson gson = new GsonBuilder().create();
+    private final Integer payloadCount;
+    private final Integer count;
+    private final String prev;
+    private final String next;
+    private final String first;
+    private final String last;
+    private final Integer insertCount;
+    private final Integer matchCount;
+    private final Integer elapsed;
+
+    public static class MetaBuilder {
+
+        private Integer payloadCount;
+        private Integer count;
+        private String prev;
+        private String next;
+        private String first;
+        private String last;
+        private Integer insertCount;
+        private Integer matchCount;
+        private Integer elapsed;
+
+        public MetaBuilder payloadCount(Integer payload) {
+            this.payloadCount = payload;
+            return this;
+        }
+
+        public MetaBuilder count(Integer count) {
+            this.count = count;
+            return this;
+        }
+
+        public MetaBuilder prev(String prevUrl) {
+            this.prev = prevUrl;
+            return this;
+        }
+
+        public MetaBuilder next(String nextUrl) {
+            this.next = nextUrl;
+            return this;
+        }
+
+        public MetaBuilder first(String firstUrl) {
+            this.first = firstUrl;
+            return this;
+        }
+
+        public MetaBuilder last(String lastUrl) {
+            this.last = lastUrl;
+            return this;
+        }
+
+        public MetaBuilder insertCount(Integer count) {
+            this.insertCount = count;
+            return this;
+        }
+
+        public MetaBuilder matchCount(Integer count) {
+            this.matchCount = count;
+            return this;
+        }
+
+        public MetaBuilder elapsed(Integer elapsed) {
+            this.elapsed = elapsed;
+            return this;
+        }
+
+        public MongoMetaDataResponseBuilder build() {
+            return new MongoMetaDataResponseBuilder(this);
+        }
+
+        public String getQueryArgumentsNoOffsetLimit(String[] URLQueryPath) {
+            StringBuilder queryString = new StringBuilder();
+            String sep = "";
+            for (String arg : URLQueryPath) {
+                if (!(arg.contains("limit") || arg.contains("offset") || arg.contains("o") || arg.contains("l"))) {
+                    queryString.append(sep).append(arg);
+                    sep = "&";
+                }
+            }
+            return queryString.toString();
+        }
+    }
+
+    private MongoMetaDataResponseBuilder(MetaBuilder builder) {
+        payloadCount = builder.payloadCount;
+        count = builder.count;
+        prev = builder.prev;
+        next = builder.next;
+        first = builder.first;
+        last = builder.last;
+        insertCount = builder.insertCount;
+        matchCount = builder.matchCount;
+        elapsed = builder.elapsed;
+    }
+
+    @Override
+    public String toString() {
+        return gson.toJson(this);
+    }
+}
\ No newline at end of file
--- a/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoResponseBuilder.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoResponseBuilder.java	Tue Jun 20 14:19:38 2017 -0400
@@ -36,52 +36,56 @@
 
 package com.redhat.thermostat.gateway.common.mongodb.response;
 
+import java.util.ArrayList;
+
 import org.bson.Document;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.mongodb.Block;
 import com.mongodb.client.FindIterable;
 
+/*
+ *  Builds the appropriate response after executing the request's MongoDB Query.
+ *
+ *  NOTE: Builder fields that aren't explicitly set - and therefore null - are omitted in the
+ *        serialized JSON.
+ */
 public class MongoResponseBuilder {
 
-    /**
-     * JSON Response format
-     * {
-     *   "response" : {
-     *       [ {...}, ... ]
-     *   }
-     * }
-     *
-     * Timed JSON Response format
-     * {
-     *   "response" : {
-     *       [ {...}, ... ]
-     *   },
-     *   "time" : elapsed
-     * }
-     */
+    private final ArrayList<Document> response;
+    private final MongoMetaDataResponseBuilder metaData;
+
+    public static class Builder {
+
+        private ArrayList<Document> queryDocuments;
+        private MongoMetaDataResponseBuilder metaData;
+        private final Gson gson = new GsonBuilder().create();
 
-    public String buildGetResponseString(FindIterable<Document> documents) {
-        final StringBuilder s = new StringBuilder();
-
-        s.append("{ \"response\" : [");
-
-        final int[] i = {0};
-
-        documents.forEach(new Block<Document>() {
-            @Override
-            public void apply(Document document) {
-                s.append(document.toJson()).append(",");
-                i[0]++;
-            }
-        });
-
-        if (i[0] != 0) {
-            s.deleteCharAt(s.length() - 1);
+        public Builder queryDocuments(FindIterable<Document> documents) {
+            queryDocuments = new ArrayList<>();
+            documents.forEach(new Block<Document>() {
+                @Override
+                public void apply(Document document) {
+                    queryDocuments.add(document);
+                }
+            });
+            return this;
         }
 
-        s.append("] }");
+        public Builder metaData(MongoMetaDataResponseBuilder metaData) {
+            this.metaData = metaData;
+            return this;
+        }
 
-        return s.toString();
+        public String build() {
+            MongoResponseBuilder data = new MongoResponseBuilder(this);
+            return gson.toJson(data);
+        }
     }
 
+    private MongoResponseBuilder(Builder builder) {
+        response = builder.queryDocuments;
+        metaData = builder.metaData;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataGeneratorTest.java	Tue Jun 20 14:19:38 2017 -0400
@@ -0,0 +1,100 @@
+/*
+ * 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.gateway.common.mongodb.response;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.gateway.common.mongodb.executor.MongoDataResultContainer;
+
+public class MongoMetaDataGeneratorTest {
+
+    private MongoMetaDataGenerator fullGenerator;
+    private MongoMetaDataResponseBuilder.MetaBuilder response;
+
+    @Before
+    public void setup() {
+        HttpServletRequest requestInfo = mock(HttpServletRequest.class);
+        when(requestInfo.getRequestURL()).thenReturn(new StringBuffer("127.0.0.1:8080/base/"));
+        when(requestInfo.getQueryString()).thenReturn("l=2&o=2&m=true");
+
+        MongoDataResultContainer container = new MongoDataResultContainer();
+        container.setRemainingNumQueryDocuments(1);
+        container.setGetReqCount(4);
+
+        fullGenerator = new MongoMetaDataGenerator(2, 2, "", "test1==b", "", requestInfo, container);
+        response = new MongoMetaDataResponseBuilder.MetaBuilder();
+    }
+
+    @Test
+    public void testSetCounts() {
+        fullGenerator.setDocAndPayloadCount(response);
+        String output = response.build().toString();
+        String expected = "{\"payloadCount\":0,\"count\":4}";
+
+        assertEquals(expected, output);
+    }
+
+    @Test
+    public void testSetPrev() {
+        fullGenerator.setPrev(response);
+        String output = response.build().toString();
+
+        // {"prev":"127.0.0.1:8080/base/?m=true&l=2&o=0"}
+        String expected = "{\"prev\":\"127.0.0.1:8080/base/?m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\"}";
+
+        assertEquals(expected, output);
+    }
+
+    @Test
+    public void testSetNext() {
+        fullGenerator.setNext(response);
+        String output = response.build().toString();
+
+        // {"payloadCount":1,"next":"127.0.0.1:8080/base/?o=4&l=1&m=true"}//{"payloadCount":1,"next":"127.0.0.1:8080/base/?o=4&l=1&m=true"}
+        String expected = "{\"payloadCount\":1,\"next\":\"127.0.0.1:8080/base/?o\\u003d4\\u0026l\\u003d1\\u0026m\\u003dtrue\"}";
+
+        assertEquals(expected, output);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoMetaDataResponseBuilderTest.java	Tue Jun 20 14:19:38 2017 -0400
@@ -0,0 +1,100 @@
+/*
+ * 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.gateway.common.mongodb.response;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MongoMetaDataResponseBuilderTest {
+
+    private MongoMetaDataResponseBuilder.MetaBuilder mongoMetaDataResponseBuilder;
+    private final String fakeUrl = "http://127.0.0.1:8080/fake/endpoint";
+
+    @Before
+    public void setup() {
+        mongoMetaDataResponseBuilder = new MongoMetaDataResponseBuilder.MetaBuilder();
+    }
+
+    @Test
+    public void testBuildGetSomeParams() {
+        mongoMetaDataResponseBuilder.payloadCount(5).count(10).next(fakeUrl);
+        String output = mongoMetaDataResponseBuilder.build().toString();
+        String expected = "{\"payloadCount\":5,\"count\":10,\"next\":\"http://127.0.0.1:8080/fake/endpoint\"}";
+        assertEquals(expected, output);
+    }
+
+    @Test
+    public void buildGetAllParams() {
+        mongoMetaDataResponseBuilder
+                .payloadCount(5)
+                .count(10)
+                .next(fakeUrl + "/5")
+                .prev(fakeUrl + "/0")
+                .elapsed(5000)
+                .first(fakeUrl + "/0")
+                .last(fakeUrl + "/10")
+                .matchCount(10)
+                .insertCount(0);
+
+        String output = mongoMetaDataResponseBuilder.build().toString();
+        String expected = "{\"payloadCount\":5,\"count\":10,\"prev\":\"http://127.0.0.1:8080/fake/endpoint/0\"," +
+                "\"next\":\"http://127.0.0.1:8080/fake/endpoint/5\",\"first\":\"http://127.0.0.1:8080/fake/endpoint/0\"" +
+                ",\"last\":\"http://127.0.0.1:8080/fake/endpoint/10\",\"insertCount\":0,\"matchCount\":10," +
+                "\"elapsed\":5000}";
+        assertEquals(expected, output);
+    }
+
+    @Test
+    public void testInitializeWithNullValue() {
+        mongoMetaDataResponseBuilder
+                .payloadCount(null)
+                .count(null)
+                .next(null)
+                .prev(null)
+                .elapsed(null)
+                .first(null)
+                .last(null)
+                .matchCount(null)
+                .insertCount(null);
+
+        String output = mongoMetaDataResponseBuilder.build().toString();
+        String expected = "{}";
+        assertEquals(expected, output);
+    }
+}
--- a/common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoResponseBuilderTest.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/common/mongodb/src/test/java/com/redhat/thermostat/gateway/common/mongodb/response/MongoResponseBuilderTest.java	Tue Jun 20 14:19:38 2017 -0400
@@ -58,11 +58,11 @@
 
 public class MongoResponseBuilderTest {
 
-    private MongoResponseBuilder mongoResponseBuilder;
+    private MongoResponseBuilder.Builder mongoResponseBuilder;
 
     @Before
     public void setup() {
-        mongoResponseBuilder = new MongoResponseBuilder();
+        mongoResponseBuilder = new MongoResponseBuilder.Builder();
     }
 
     @Test
@@ -75,8 +75,8 @@
 
         FindIterable<Document> iterable = new TestFindIterable<>(list);
 
-        String output = mongoResponseBuilder.buildGetResponseString(iterable);
-        String expected = "{ \"response\" : [{ \"hello\" : \"blob\" },{ \"a\" : { \"blob\" : [\"hi\"] } }] }";
+        String output = mongoResponseBuilder.queryDocuments(iterable).build();
+        String expected = "{\"response\":[{\"hello\":\"blob\"},{\"a\":{\"blob\":[\"hi\"]}}]}";
         assertEquals(expected, output);
     }
 
@@ -84,8 +84,8 @@
     public void testBuildEmptyGetResponse() {
         FindIterable<Document> iterable = new TestFindIterable<>(Collections.<Document>emptyList());
 
-        String output = mongoResponseBuilder.buildGetResponseString(iterable);
-        String expected = "{ \"response\" : [] }";
+        String output = mongoResponseBuilder.queryDocuments(iterable).build();
+        String expected = "{\"response\":[]}";
         assertEquals(expected, output);
     }
 
--- a/services/jvm-gc/src/main/java/com/redhat/thermostat/service/jvm/gc/JvmGcHttpHandler.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/services/jvm-gc/src/main/java/com/redhat/thermostat/service/jvm/gc/JvmGcHttpHandler.java	Tue Jun 20 14:19:38 2017 -0400
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.service.jvm.gc;
 
 import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
@@ -49,11 +50,14 @@
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 
-
 import com.mongodb.DBObject;
 import com.redhat.thermostat.gateway.common.mongodb.ThermostatMongoStorage;
 import com.redhat.thermostat.gateway.common.mongodb.executor.MongoExecutor;
+import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataResponseBuilder;
+import com.redhat.thermostat.gateway.common.mongodb.response.MongoResponseBuilder;
+import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataGenerator;
 import com.redhat.thermostat.gateway.common.mongodb.servlet.ServletContextConstants;
+import com.redhat.thermostat.gateway.common.mongodb.executor.MongoDataResultContainer;
 
 @Path("/")
 public class JvmGcHttpHandler {
@@ -63,35 +67,49 @@
     @GET
     @Consumes({ "application/json" })
     @Produces({ "application/json", "text/html; charset=utf-8" })
-    public Response getJvmMemory(@QueryParam("l") @DefaultValue("1") Integer limit,
-                                 @QueryParam("o") @DefaultValue("0") Integer offset,
-                                 @QueryParam("s") String sort,
-                                 @QueryParam("q") String queries,
-                                 @QueryParam("p") String projections,
-                                 @Context ServletContext context
-    ) {
+    public Response getJvmGc(@QueryParam("l") @DefaultValue("1") Integer limit,
+                             @QueryParam("o") @DefaultValue("0") Integer offset,
+                             @QueryParam("s") String sort,
+                             @QueryParam("q") String queries,
+                             @QueryParam("p") String projections,
+                             @QueryParam("m") @DefaultValue("false") Boolean metadata,
+                             @Context HttpServletRequest requestInfo,
+                             @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
+            MongoDataResultContainer execResult = mongoExecutor.execGetRequest(
+                    storage.getDatabase().getCollection(collectionName), limit, offset, sort, queries, projections);
 
-            String message = mongoExecutor.buildGetResponse(storage.getDatabase().getCollection(collectionName), limit, offset, sort, queries, projections);
+            MongoResponseBuilder.Builder response = new MongoResponseBuilder.Builder();
+            response.queryDocuments(execResult.getQueryDataResult());
 
-            return Response.status(Response.Status.OK).entity(message).build();
+            if (metadata) {
+                MongoMetaDataResponseBuilder.MetaBuilder metaDataResponse = new MongoMetaDataResponseBuilder.MetaBuilder();
+                MongoMetaDataGenerator metaDataGenerator = new MongoMetaDataGenerator(limit, offset, sort, queries,
+                        projections, requestInfo, execResult);
+
+                metaDataGenerator.setDocAndPayloadCount(metaDataResponse);
+                metaDataGenerator.setPrev(metaDataResponse);
+                metaDataGenerator.setNext(metaDataResponse);
+
+                response.metaData(metaDataResponse.build());
+            }
+            return Response.status(Response.Status.OK).entity(response.build()).build();
         } catch (Exception e) {
-            return Response.status(Response.Status.BAD_REQUEST).build();
+            return Response.status(Response.Status.BAD_REQUEST).entity(e.getStackTrace()).build();
         }
     }
 
     @PUT
     @Consumes({ "application/json" })
     @Produces({ "application/json", "text/html; charset=utf-8" })
-    public Response putJvmMemory(String body,
-                                 @QueryParam("q") String queries,
-                                 @Context ServletContext context) {
+    public Response putJvmGc(String body,
+                             @QueryParam("q") String queries,
+                             @QueryParam("m") @DefaultValue("false") String metadata,
+                             @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
-
-            mongoExecutor.buildPutResponse(storage.getDatabase().getCollection(collectionName), body, queries);
-
+            mongoExecutor.execPutRequest(storage.getDatabase().getCollection(collectionName), body, queries);
             return Response.status(Response.Status.OK).build();
         } catch (Exception e) {
             return Response.status(Response.Status.BAD_REQUEST).build();
@@ -101,12 +119,12 @@
     @POST
     @Consumes({ "application/json" })
     @Produces({ "application/json", "text/html; charset=utf-8" })
-    public Response postJvmMemory(String body,
-                                  @Context ServletContext context) {
+    public Response postJvmGc(String body,
+                              @QueryParam("m") @DefaultValue("false") String metadata,
+                              @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
-
-            mongoExecutor.buildPost(storage.getDatabase().getCollection(collectionName, DBObject.class), body);
+            mongoExecutor.execPostRequest(storage.getDatabase().getCollection(collectionName, DBObject.class), body);
             return Response.status(Response.Status.OK).build();
         } catch (Exception e) {
             return Response.status(Response.Status.BAD_REQUEST).build();
@@ -116,13 +134,12 @@
     @DELETE
     @Consumes({ "application/json" })
     @Produces({ "application/json", "text/html; charset=utf-8" })
-    public Response deleteJvmMemory(@QueryParam("q") String queries,
-                                    @Context ServletContext context) {
+    public Response deleteJvmGc(@QueryParam("q") String queries,
+                                @QueryParam("m") @DefaultValue("false") String metadata,
+                                @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
-
-            mongoExecutor.buildDeleteResponse(storage.getDatabase().getCollection(collectionName), queries);
-
+            mongoExecutor.execDeleteRequest(storage.getDatabase().getCollection(collectionName), queries);
             return Response.status(Response.Status.OK).build();
         } catch (Exception e) {
             return Response.status(Response.Status.BAD_REQUEST).build();
--- a/services/jvm-memory/src/main/java/com/redhat/thermostat/service/jvm/memory/JvmMemoryHttpHandler.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/services/jvm-memory/src/main/java/com/redhat/thermostat/service/jvm/memory/JvmMemoryHttpHandler.java	Tue Jun 20 14:19:38 2017 -0400
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.service.jvm.memory;
 
 import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
@@ -48,15 +49,17 @@
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
-
 import com.mongodb.DBObject;
 import com.redhat.thermostat.gateway.common.mongodb.ThermostatMongoStorage;
 import com.redhat.thermostat.gateway.common.mongodb.executor.MongoExecutor;
+import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataResponseBuilder;
+import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataGenerator;
+import com.redhat.thermostat.gateway.common.mongodb.response.MongoResponseBuilder;
 import com.redhat.thermostat.gateway.common.mongodb.servlet.ServletContextConstants;
+import com.redhat.thermostat.gateway.common.mongodb.executor.MongoDataResultContainer;
 
 @Path("/")
 public class JvmMemoryHttpHandler {
-
     private final MongoExecutor mongoExecutor = new MongoExecutor();
     private final String collectionName = "jvm-memory";
 
@@ -68,14 +71,29 @@
                                  @QueryParam("s") String sort,
                                  @QueryParam("q") String queries,
                                  @QueryParam("p") String projections,
-                                 @Context ServletContext context
-    ) {
+                                 @QueryParam("m") @DefaultValue("false") Boolean metadata,
+                                 @Context ServletContext context,
+                                 @Context HttpServletRequest requestInfo) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
+            MongoDataResultContainer execResult = mongoExecutor.execGetRequest(
+                    storage.getDatabase().getCollection(collectionName), limit, offset, sort, queries, projections);
 
-            String message = mongoExecutor.buildGetResponse(storage.getDatabase().getCollection(collectionName), limit, offset, sort, queries, projections);
+            MongoResponseBuilder.Builder response = new MongoResponseBuilder.Builder();
+            response.queryDocuments(execResult.getQueryDataResult());
+            if (metadata) {
+                MongoMetaDataResponseBuilder.MetaBuilder metaDataResponse = new MongoMetaDataResponseBuilder.MetaBuilder();
+
+                MongoMetaDataGenerator metaDataGenerator = new MongoMetaDataGenerator(limit, offset, sort, queries,
+                        projections, requestInfo, execResult);
 
-            return Response.status(Response.Status.OK).entity(message).build();
+                metaDataGenerator.setDocAndPayloadCount(metaDataResponse);
+                metaDataGenerator.setPrev(metaDataResponse);
+                metaDataGenerator.setNext(metaDataResponse);
+
+                response.metaData(metaDataResponse.build());
+            }
+            return Response.status(Response.Status.OK).entity(response.build()).build();
         } catch (Exception e) {
             return Response.status(Response.Status.BAD_REQUEST).build();
         }
@@ -86,11 +104,12 @@
     @Produces({ "application/json", "text/html; charset=utf-8" })
     public Response putJvmMemory(String body,
                                  @QueryParam("q") String queries,
+                                 @QueryParam("m") @DefaultValue("false") String metadata,
                                  @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
 
-            mongoExecutor.buildPutResponse(storage.getDatabase().getCollection(collectionName), body, queries);
+            MongoDataResultContainer putExec = mongoExecutor.execPutRequest(storage.getDatabase().getCollection(collectionName), body, queries);
 
             return Response.status(Response.Status.OK).build();
         } catch (Exception e) {
@@ -102,11 +121,12 @@
     @Consumes({ "application/json" })
     @Produces({ "application/json", "text/html; charset=utf-8" })
     public Response postJvmMemory(String body,
+                                  @QueryParam("m") @DefaultValue("false") String metadata,
                                   @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
 
-            mongoExecutor.buildPost(storage.getDatabase().getCollection(collectionName, DBObject.class), body);
+            mongoExecutor.execPostRequest(storage.getDatabase().getCollection(collectionName, DBObject.class), body);
             return Response.status(Response.Status.OK).build();
         } catch (Exception e) {
             return Response.status(Response.Status.BAD_REQUEST).build();
@@ -117,11 +137,12 @@
     @Consumes({ "application/json" })
     @Produces({ "application/json", "text/html; charset=utf-8" })
     public Response deleteJvmMemory(@QueryParam("q") String queries,
+                                    @QueryParam("m") @DefaultValue("false") String metadata,
                                     @Context ServletContext context) {
         try {
             ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
 
-            mongoExecutor.buildDeleteResponse(storage.getDatabase().getCollection(collectionName), queries);
+            MongoDataResultContainer delExec = mongoExecutor.execDeleteRequest(storage.getDatabase().getCollection(collectionName), queries);
 
             return Response.status(Response.Status.OK).build();
         } catch (Exception e) {
--- a/services/jvms/src/main/java/com/redhat/thermostat/service/jvms/mongo/MongoStorageHandler.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/services/jvms/src/main/java/com/redhat/thermostat/service/jvms/mongo/MongoStorageHandler.java	Tue Jun 20 14:19:38 2017 -0400
@@ -69,7 +69,7 @@
 public class MongoStorageHandler {
 
     private static final String SET_KEY = "$set";
-    private final MongoResponseBuilder mongoResponseBuilder = new MongoResponseBuilder();
+    private final MongoResponseBuilder.Builder mongoResponseBuilder = new MongoResponseBuilder.Builder();
 
     public String getJvmInfos(MongoCollection<Document> collection, String systemId, Integer limit, Integer offset, String sort, String queries, String includes, String excludes) {
         Bson baseQuery = eq(Fields.SYSTEM_ID, systemId);
@@ -87,7 +87,7 @@
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     public String getJvmInfo(MongoCollection<Document> collection, String systemId, String jvmId, String includes, String excludes) {
@@ -98,7 +98,7 @@
 
         documents = documents.limit(1).skip(0).batchSize(1).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     private FindIterable<Document> buildProjection(FindIterable<Document> documents, String includes, String excludes) {
--- a/services/system-cpu/src/main/java/com/redhat/thermostat/service/cpuinfo/mongo/MongoStorageHandler.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/services/system-cpu/src/main/java/com/redhat/thermostat/service/cpuinfo/mongo/MongoStorageHandler.java	Tue Jun 20 14:19:38 2017 -0400
@@ -62,7 +62,7 @@
 
 public class MongoStorageHandler {
 
-    private final MongoResponseBuilder mongoResponseBuilder = new MongoResponseBuilder();
+    private final MongoResponseBuilder.Builder mongoResponseBuilder = new MongoResponseBuilder.Builder();
 
     public String getMany(MongoCollection<Document> collection, Integer limit, Integer offset, String sort, String queries, String includes, String excludes) {
         FindIterable<Document> documents;
@@ -79,7 +79,7 @@
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     public String getOne(MongoCollection<Document> collection, String systemId, Integer limit, Integer offset, String sort, String includes, String excludes) {
@@ -91,7 +91,7 @@
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit + offset).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     private FindIterable<Document> buildProjection(FindIterable<Document> documents, String includes, String excludes) {
--- a/services/system-memory/src/main/java/com/redhat/thermostat/service/systemmemory/mongo/MongoStorageHandler.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/services/system-memory/src/main/java/com/redhat/thermostat/service/systemmemory/mongo/MongoStorageHandler.java	Tue Jun 20 14:19:38 2017 -0400
@@ -63,7 +63,7 @@
 
 public class MongoStorageHandler {
 
-    private final MongoResponseBuilder mongoResponseBuilder = new MongoResponseBuilder();
+    private final MongoResponseBuilder.Builder mongoResponseBuilder = new MongoResponseBuilder.Builder();
 
     public String getOne(MongoCollection<Document> collection, String systemId, Integer limit, Integer offset, String sort, String includes, String excludes) {
         Bson query = eq(Fields.SYSTEM_ID, systemId);
@@ -74,7 +74,7 @@
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit + offset).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     private FindIterable<Document> buildProjection(FindIterable<Document> documents, String includes, String excludes) {
--- a/services/systems/src/main/java/com/redhat/thermostat/service/systems/mongo/MongoStorageHandler.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/services/systems/src/main/java/com/redhat/thermostat/service/systems/mongo/MongoStorageHandler.java	Tue Jun 20 14:19:38 2017 -0400
@@ -62,7 +62,7 @@
 
 public class MongoStorageHandler {
 
-    private final MongoResponseBuilder mongoResponseBuilder = new MongoResponseBuilder();
+    private final MongoResponseBuilder.Builder mongoResponseBuilder = new MongoResponseBuilder.Builder();
 
     public String getSystemInfos(MongoCollection<Document> collection, Integer limit, Integer offset, String sort, String queries, String includes, String excludes) {
         FindIterable<Document> documents;
@@ -79,7 +79,7 @@
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     public String getSystemInfo(MongoCollection<Document> collection, String systemId, Integer limit, Integer offset, String sort, String includes, String excludes) {
@@ -91,7 +91,7 @@
         final Bson sortObject = MongoSortFilters.createSortObject(sort);
         documents = documents.sort(sortObject).limit(limit).skip(offset).batchSize(limit + offset).cursorType(CursorType.NonTailable);
 
-        return mongoResponseBuilder.buildGetResponseString(documents);
+        return mongoResponseBuilder.queryDocuments(documents).build();
     }
 
     private FindIterable<Document> buildProjection(FindIterable<Document> documents, String includes, String excludes) {
--- a/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/gc/JvmGcServiceIntegrationTest.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/gc/JvmGcServiceIntegrationTest.java	Tue Jun 20 14:19:38 2017 -0400
@@ -88,88 +88,242 @@
 
     @Test
     public void testGet() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", data, "application/json", "", 200);
-        makeHttpGetRequest(gcUrl, "{ \"response\" : [{ \"a\" : \"test\", \"b\" : \"test1\", \"c\" : \"test2\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl,"{\"response\":[{\"a\":\"test\",\"b\":\"test1\","+
+                "\"c\":\"test2\"}]}", 200);
     }
 
     @Test
     public void testGetLimitParam() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", data, "application/json", "", 200);
-        makeHttpGetRequest(gcUrl + "?l=2", "{ \"response\" : [{ \"a\" : \"test\", \"b\" : \"test1\", " +
-                        "\"c\" : \"test2\" },{ \"d\" : \"test3\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?l=2","{\"response\":[{\"a\":\"test\",\"b\":"+
+                "\"test1\",\"c\":\"test2\"},{\"d\":\"test3\"}]}", 200);
     }
 
     @Test
     public void testGetSortParam() throws InterruptedException, TimeoutException, ExecutionException {
-        String data = "[{ \"a\" : \"1\"}, {\"a\" : \"2\"}]";
+        String data ="[{\"a\":\"1\"}, {\"a\":\"2\"}]";
 
-        makeHttpMethodRequest(HttpMethod.POST, "", data,"application/json", "", 200);
-        makeHttpGetRequest(gcUrl + "?l=3&s=-a", "{ \"response\" : [{ \"a\" : \"2\" },{ \"a\" : \"1\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?l=3&s=-a","{\"response\":[{\"a\":\"2\"},{\"a\":"+
+                "\"1\"}]}", 200);
     }
 
     @Test
     public void testGetProjectParam() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", data, "application/json", "", 200);
-        makeHttpGetRequest(gcUrl + "?p=b,c", "{ \"response\" : [{ \"b\" : \"test1\", \"c\" : \"test2\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?p=b,c","{\"response\":[{\"b\":\"test1\",\"c\":"+
+                "\"test2\"}]}", 200);
     }
 
     @Test
     public void testGetOffsetParam() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", data, "application/json", "", 200);
-        makeHttpGetRequest(gcUrl + "?o=1", "{ \"response\" : [{ \"d\" : \"test3\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?o=1","{\"response\":[{\"d\":\"test3\"}]}", 200);
     }
 
     @Test
     public void testGetQueryParam() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", data,"application/json", "", 200);
-        makeHttpGetRequest(gcUrl + "?q=b==test1", "{ \"response\" : [{ \"a\" : \"test\", \"b\" : \"test1\"," +
-                " \"c\" : \"test2\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1","{\"response\":[{\"a\":\"test\",\"b\":"+
+                "\"test1\",\"c\":\"test2\"}]}", 200);
     }
 
     @Test
     public void testPostJSON() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", "[{ \"f1\" : \"test\" }]", "application/json",
-                "{ \"response\" : [{ \"f1\" : \"test\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"?m=true","[{\"f1\":\"test\"}]","application/json",
+                "{\"response\":[{\"f1\":\"test\"}]}", 200);
     }
 
     @Test
     public void testPostXML() throws InterruptedException,TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", "", "application/xml", "", 415);
+        makeHttpMethodRequest(HttpMethod.POST,"","","application/xml","", 415);
     }
 
     @Test
     public void testInvalidDataPost() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", "{ \"badFormat\" : \"missing square brackets\" }",
-                "application/json", "", 400);
+        makeHttpMethodRequest(HttpMethod.POST,"","{\"badFormat\":\"missing square brackets\"}",
+                "application/json","", 400);
     }
 
     @Test
     public void testDelete() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.DELETE, "", "", "", "", 200);
+        makeHttpMethodRequest(HttpMethod.DELETE,"","","","", 200);
     }
 
     @Test
     public void testNonExistentDataDelete() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.DELETE, "?q=nonExist==Null", "", "", "", 200);
+        makeHttpMethodRequest(HttpMethod.DELETE,"?q=nonExist==Null","","","", 200);
     }
 
     @Test
     public void testPostPutDeleteMockedData() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", "[{ \"f1\" : \"test\" }]", "application/json",
-                "{ \"response\" : [{ \"f1\" : \"test\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"","[{\"f1\":\"test\"}]","application/json",
+                "{\"response\":[{\"f1\":\"test\"}]}", 200);
+
+        makeHttpMethodRequest(HttpMethod.PUT,"?q=f1==test","{\"set\": {\"f1\":\"newdata\"}}",
+                "application/json","{\"response\":[{\"f1\":\"newdata\"}]}", 200);
+
+        makeHttpMethodRequest(HttpMethod.DELETE,"?q=f1==test","","","", 200);
+    }
+
+    @Test
+    public void testGetWithMetaDataAndLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}]";
+
+        // {"response":["{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}"],
+        //"metaData":{"payloadCount":1,"count":3,
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=1&l=1&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}],"+
+                "\"metaData\":{\"payloadCount\":1,\"count\":3,"+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d1\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&l=1", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetWithMetaDataAndOffset() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}"],"metaData":{"payloadCount":1,"count":3,
+        //"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=1",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=2&l=1&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":1,\"count\":3,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d1\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d2\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
 
-        makeHttpMethodRequest(HttpMethod.PUT, "?q=f1==test", "{ \"set\" : { \"f1\" : \"newdata\" }}",
-                "application/json", "{ \"response\" : [{ \"f1\" : \"newdata\" }] }", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=1", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetMetDatPrevOffsetBiggerThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":1,"count":6,"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=2&o=1",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=5&l=1&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"b\":\"test1\"},{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":1,\"count\":6,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d1\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d5\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
 
-        makeHttpMethodRequest(HttpMethod.DELETE, "?q=f1==test", "", "", "", 200);
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=3&l=2", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetMetDatPrevOffsetEqualToLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":1,"count":3,"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=1",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=2&l=1&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":1,\"count\":3,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d1\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d2\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=1&l=1", expectedResponse, 200);
     }
 
     @Test
-    public void testPutIdenticalPreexistingData() throws InterruptedException, TimeoutException, ExecutionException {
-        makeHttpMethodRequest(HttpMethod.POST, "", "[{ \"f2\" : \"identical\" }]",
-                "application/json", "{ \"response\" : [{ \"f2\" : \"identical\" }] }", 200);
+    public void testGetMetDatNextOffsetLessThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"e\":\"test4\",\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":2,"count":6,"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=1&o=0",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=3&l=2&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"b\":\"test1\"},{\"e\":\"test4\",\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":2,\"count\":6,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d1\\u0026o\\u003d0\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d3\\u0026l\\u003d2\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=1&l=2", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetMetDatNextOffsetBiggerThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":1,"count":6,
+        //"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=2&o=1",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=5&l=1&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"b\":\"test1\"},{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":1,\"count\":6,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d1\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d5\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=3&l=2", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetMetDatNextOffsetEqualToLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"}]";
 
-        makeHttpMethodRequest(HttpMethod.PUT,"?q=f2==identical","{ \"set\" : { \"f2\" : \"identical\" }}",
-                "application/json","{ \"response\" : [{ \"f2\" : \"identical\" }] }", 200);
+        // {"response":["{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":2,"count":6,"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=2&o=0",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=4&l=2&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"e\":\"test4\",\"b\":\"test1\"},{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":2,\"count\":6,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d4\\u0026l\\u003d2\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=2&l=2", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetMetDatNextExtremity() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":2,"count":6,
+        //"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=2&o=0",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=4&l=2&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"e\":\"test4\",\"b\":\"test1\"},{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":2,\"count\":6,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d4\\u0026l\\u003d2\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=2&l=2", expectedResponse, 200);
+    }
+
+    @Test
+    public void testGetMetDatPrevExtremity() throws InterruptedException, TimeoutException, ExecutionException {
+        String data ="[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"},"+
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"}]";
+
+
+        // {"response":["{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        //"metaData":{"payloadCount":1,"count":6,"prev":"http://127.0.0.1:30000/jvm-gc/0.0.2?q===test1&m=true&l=2&o=0",
+        //"next":"http://127.0.0.1:30000/jvm-gc/0.0.2?o=5&l=1&q===test1&m=true"}}
+        String expectedResponse ="{\"response\":[{\"e\":\"test4\",\"b\":\"test1\"},"+
+                "{\"b\":\"test1\"},{\"b\":\"test1\"}],"+
+                "\"metaData\":{\"payloadCount\":1,\"count\":6,"+
+                "\"prev\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\","+
+                "\"next\":\"http://127.0.0.1:30000/jvm-gc/0.0.2?o\\u003d5\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+        makeHttpMethodRequest(HttpMethod.POST,"", data,"application/json","", 200);
+        makeHttpGetRequest(gcUrl +"?q=b==test1&m=true&o=2&l=3", expectedResponse, 200);
     }
 }
--- a/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/memory/JvmMemoryServiceIntegrationTest.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/memory/JvmMemoryServiceIntegrationTest.java	Tue Jun 20 14:19:38 2017 -0400
@@ -70,50 +70,50 @@
 
     @Test
     public void testPostProperlyAddsData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedResponse = "{ \"response\" : [{ \"fakedata\" : \"test\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"fakedata\" : \"test\" }]", 200);
+        String expectedResponse = "{\"response\":[{\"fakedata\":\"test\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"fakedata\":\"test\"}]", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedResponse);
     }
 
     @Test
     public void testMultiplePosts() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedResponse = "{ \"response\" : [{ \"fakedata\" : \"test\" },{ \"new\" : \"data\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"fakedata\" : \"test\" }]", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"new\" : \"data\" }]", 200);
+        String expectedResponse = "{\"response\":[{\"fakedata\":\"test\"},{\"new\":\"data\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"fakedata\":\"test\"}]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"new\":\"data\"}]", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=5", 200, expectedResponse);
     }
 
     @Test
     public void testPostPutAddsData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedDataBeforePut = "{ \"response\" : [{ \"a\" : \"b\" }] }";
-        String expectedDataAfterPut = "{ \"response\" : [{ \"a\" : \"b\", \"x\" : \"y\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"a\" : \"b\" }]", 200);
+        String expectedDataBeforePut = "{\"response\":[{\"a\":\"b\"}]}";
+        String expectedDataAfterPut = "{\"response\":[{\"a\":\"b\",\"x\":\"y\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"a\":\"b\"}]", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataBeforePut);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==b", "{ \"set\" : { \"x\" : \"y\" }}", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==b", "{\"set\":{\"x\":\"y\"}}", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataAfterPut);
     }
 
     @Test
     public void testPostPutModifiesData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedDataBeforePut = "{ \"response\" : [{ \"a\" : \"b\" }] }";
-        String expectedDataAfterPut = "{ \"response\" : [{ \"a\" : \"c\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"a\" : \"b\" }]", 200);
+        String expectedDataBeforePut = "{\"response\":[{\"a\":\"b\"}]}";
+        String expectedDataAfterPut = "{\"response\":[{\"a\":\"c\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"a\":\"b\"}]", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataBeforePut);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==b", "{ \"set\" : { \"a\" : \"c\" }}", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==b", "{\"set\":{\"a\":\"c\"}}", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataAfterPut);
     }
 
     @Test
     public void testDeleteProperlyDeletesData() throws InterruptedException, TimeoutException, ExecutionException {
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"fakedata\" : \"test\" }]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"fakedata\":\"test\"}]", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.DELETE, resourceUrl + "?q=fakedata==test", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, HttpTestUtil.EMPTY_RESPONSE);
     }
 
     @Test
     public void testMalformedDeleteRequestDoesNotMutateData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedDataResponse = "{ \"response\" : [{ \"fakedata\" : \"test\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"fakedata\" : \"test\" }]", 200);
+        String expectedDataResponse = "{\"response\":[{\"fakedata\":\"test\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"fakedata\":\"test\"}]", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataResponse);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.DELETE, resourceUrl + "?q=nosuchkey==", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataResponse);
@@ -121,41 +121,41 @@
 
     @Test
     public void testPutDataWithoutUrlQuery() throws InterruptedException, TimeoutException, ExecutionException {
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"fakedata\" : \"test\" }]", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl, "{ \"set\" : { \"fakedata\" : \"test\" }}", 400);
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"fakedata\":\"test\"}]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl, "{\"set\":{\"fakedata\":\"test\"}}", 400);
     }
 
     @Test
     public void testPostAndPutWithInvalidData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedDataResponse = "{ \"response\" : [{ \"fakedata\" : \"test\" }] }";
+        String expectedDataResponse = "{\"response\":[{\"fakedata\":\"test\"}]}";
         String urlQuery = resourceUrl + "?q=nosuchkey==nosuchvalue";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, urlQuery, "[{ \"fakedata\" : \"test\" }]", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, urlQuery, "{ \"set\" : { \"fakedata\" : \"somethingnew\" }}", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, urlQuery, "[{\"fakedata\":\"test\"}]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, urlQuery, "{\"set\":{\"fakedata\":\"somethingnew\"}}", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=5", 200, expectedDataResponse);
     }
 
     @Test
     public void testPutWithIdenticalData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedDataResponse = "{ \"response\" : [{ \"fakedata\" : \"test\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"fakedata\" : \"test\" }]", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl, "{ \"set\" : { \"fakedata\" : \"test\" }}", 400);
+        String expectedDataResponse = "{\"response\":[{\"fakedata\":\"test\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"fakedata\":\"test\"}]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl, "{\"set\":{\"fakedata\":\"test\"}}", 400);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=5", 200, expectedDataResponse);
     }
 
     @Test
     public void testPutDifferentData() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedDataResponse = "{ \"response\" : [{ \"a\" : \"b\", \"c\" : \"d\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"a\" : \"b\" }]", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==b", "{ \"set\" : { \"c\" : \"d\" }}", 200);
+        String expectedDataResponse = "{\"response\":[{\"a\":\"b\",\"c\":\"d\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"a\":\"b\"}]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==b", "{\"set\":{\"c\":\"d\"}}", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=5", 200, expectedDataResponse);
     }
 
     @Test
     public void testChangeDataWithPutMultipleTimes() throws InterruptedException, TimeoutException, ExecutionException {
-        String expectedData = "{ \"response\" : [{ \"a\" : \"a2\", \"b\" : \"b2\", \"c\" : \"c2\" }] }";
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"a\" : \"a2\" }]", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==a2", "{ \"set\" : { \"b\" : \"b2\" }}", 200);
-        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==a2", "{ \"set\" : { \"c\" : \"c2\" }}", 200);
+        String expectedData = "{\"response\":[{\"a\":\"a2\",\"b\":\"b2\",\"c\":\"c2\"}]}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"a\":\"a2\"}]", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==a2", "{\"set\":{\"b\":\"b2\"}}", 200);
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, resourceUrl + "?q=a==a2", "{\"set\":{\"c\":\"c2\"}}", 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=5", 200, expectedData);
     }
 
@@ -166,9 +166,9 @@
 
     @Test
     public void testGetLimitWithQuery() throws InterruptedException, TimeoutException, ExecutionException {
-        String data = "[{ \"a\" : \"a2\" },{ \"b\" : \"b2\" }]";
-        String expectedDataOne = "{ \"response\" : [{ \"a\" : \"a2\" }] }";
-        String expectedDataAll = "{ \"response\" : " + data + " }";
+        String data = "[{\"a\":\"a2\"},{\"b\":\"b2\"}]";
+        String expectedDataOne = "{\"response\":[{\"a\":\"a2\"}]}";
+        String expectedDataAll = "{\"response\":[{\"a\":\"a2\"},{\"b\":\"b2\"}]}";
         HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl, 200, expectedDataOne);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=2", 200, expectedDataAll);
@@ -176,15 +176,15 @@
 
     @Test
     public void testQueryOffset() throws InterruptedException, TimeoutException, ExecutionException {
-        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{ \"a\" : \"1\" } , {\"b\" : \"2\"}, {\"c\" : \"3\"}]", 200);
-        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?o=1", 200, "{ \"response\" : [{ \"b\" : \"2\" }] }");
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, "[{\"a\":\"1\"} , {\"b\":\"2\"}, {\"c\":\"3\"}]", 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?o=1", 200, "{\"response\":[{\"b\":\"2\"}]}");
     }
 
     @Test
     public void testQueryOrdering() throws InterruptedException, TimeoutException, ExecutionException {
-        String content = "[{ \"a\" : 1 },{ \"a\" : 2 }]";
-        String expectedGet = "{ \"response\" : " + content + " }";
-        String expectedGetReverse = "{ \"response\" : [{ \"a\" : 2 },{ \"a\" : 1 }] }";
+        String content = "[{\"a\":1 },{\"a\":2 }]";
+        String expectedGet = "{\"response\":[{\"a\":1},{\"a\":2}]}";
+        String expectedGetReverse = "{\"response\":[{\"a\":2},{\"a\":1}]}";
         HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, content, 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=10&s=+a", 200, expectedGet);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?l=10&s=-a", 200, expectedGetReverse);
@@ -192,9 +192,194 @@
 
     @Test
     public void testQueryProjection() throws InterruptedException, TimeoutException, ExecutionException {
-        String content = "[{ \"a\" : \"1\", \"b\" : \"2\", \"c\" : \"3\" }]";
-        String expectedGet = "{ \"response\" : [{ \"b\" : \"2\", \"c\" : \"3\" }] }";
+        String content = "[{\"a\":\"1\",\"b\":\"2\",\"c\":\"3\"}]";
+        String expectedGet = "{\"response\":[{\"b\":\"2\",\"c\":\"3\"}]}";
         HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, content, 200);
         HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?p=b,c", 200, expectedGet);
     }
+
+    @Test
+    public void testGetWithMetaDataAndLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}]";
+
+        // {"response":["{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}"],
+        // "metaData":{"payloadCount":1,"count":3,
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=1&l=1&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"a\":\"test\",\"b\":\"test1\"," +
+                "\"c\":\"test2\"}],\"metaData\":{\"payloadCount\":1,\"count\":3," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d1\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&l=1", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetWithMetaDataAndOffset() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}"],"metaData":{"payloadCount":1,"count":3,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=1",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=2&l=1&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":1,\"count\":3," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d1\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d2\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=1", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatPrevOffsetLessThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":1,"count":5,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=1&o=0",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=4&l=1&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"b\":\"test1\"},{\"e\":\"test4\"," +
+                "\"b\":\"test1\"},{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":1,\"count\":5," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue" +
+                "\\u0026l\\u003d1\\u0026o\\u003d0\",\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d4" +
+                "\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=1&l=3", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatPrevOffsetBiggerThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}, " +
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":1,"count":6,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=2&o=1",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=5&l=1&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"b\":\"test1\"},{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":1,\"count\":6," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d1\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d5\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=3&l=2", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatPrevOffsetEqualToLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":1,"count":3,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=1",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=2&l=1&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":1,\"count\":3," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d1\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d2\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=1&l=1", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatNextOffsetLessThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}, " +
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"e\":\"test4\",\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":2,"count":6,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=1&o=0",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=3&l=2&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"b\":\"test1\"},{\"e\":\"test4\"," +
+                "\"b\":\"test1\"}],\"metaData\":{\"payloadCount\":2,\"count\":6," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d1\\u0026o\\u003d0\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d3\\u0026l\\u003d2\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=1&l=2", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatNextOffsetBiggerThanLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}, " +
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":1,"count":6,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=2&o=1",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=5&l=1&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"b\":\"test1\"},{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":1,\"count\":6," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d1\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d5\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=3&l=2", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatNextOffsetEqualToLimit() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}, " +
+                "{\"b\":\"test1\"}]";
+        // {"response":["{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":2,"count":6,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=2&o=0",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=4&l=2&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"e\":\"test4\",\"b\":\"test1\"},{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":2,\"count\":6," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d4\\u0026l\\u003d2\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=2&l=2", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatNextExtremity() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}, " +
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}"],
+        // "metaData":{"payloadCount":2,"count":6,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q===test1&m=true&l=2&o=0",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=4&l=2&q===test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"e\":\"test4\",\"b\":\"test1\"},{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":2,\"count\":6," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d4\\u0026l\\u003d2\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=2&l=2", 200, expectedResponse);
+    }
+
+    @Test
+    public void testGetMetDatPrevExtremity() throws InterruptedException, TimeoutException, ExecutionException {
+        String data = "[{\"a\":\"test\",\"b\":\"test1\",\"c\":\"test2\"}, {\"b\":\"test1\"}," +
+                "{\"e\":\"test4\",\"b\":\"test1\"}, {\"b\":\"test1\"}, {\"b\":\"test1\"}, " +
+                "{\"b\":\"test1\"}]";
+
+        // {"response":["{\"e\":\"test4\",\"b\":\"test1\"}","{\"b\":\"test1\"}","{\"b\":\"test1\"}"],"
+        // metaData":{"payloadCount":1,"count":6,
+        // "prev":"http://127.0.0.1:30000/jvm-memory/0.0.2?q=b==test1&m=true&l=2&o=0",
+        // "next":"http://127.0.0.1:30000/jvm-memory/0.0.2?o=5&l=1&q=b==test1&m=true"}}
+        String expectedResponse = "{\"response\":[{\"e\":\"test4\",\"b\":\"test1\"}," +
+                "{\"b\":\"test1\"},{\"b\":\"test1\"}]," +
+                "\"metaData\":{\"payloadCount\":1,\"count\":6," +
+                "\"prev\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\\u0026l\\u003d2\\u0026o\\u003d0\"," +
+                "\"next\":\"http://127.0.0.1:30000/jvm-memory/0.0.2?o\\u003d5\\u0026l\\u003d1\\u0026q\\u003db\\u003d\\u003dtest1\\u0026m\\u003dtrue\"}}";
+
+        HttpTestUtil.testContentResponse(client, HttpMethod.POST, resourceUrl, data, 200);
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, resourceUrl + "?q=b==test1&m=true&o=2&l=3", 200, expectedResponse);
+    }
 }
--- a/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvms/JvmsServiceIntegrationTest.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvms/JvmsServiceIntegrationTest.java	Tue Jun 20 14:19:38 2017 -0400
@@ -87,13 +87,12 @@
     public JvmsServiceIntegrationTest() {
         super(jvmsUrl, "jvm-info");
     }
-
     @Test
     public void testGetEmpty() throws InterruptedException, TimeoutException, ExecutionException {
         String url = jvmsUrl + "/systems/1";
         ContentResponse response = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, response.getStatus());
-        String expected = "{ \"response\" : [] }";
+        String expected = "{\"response\":[]}";
         assertEquals(expected, response.getContentAsString());
     }
 
@@ -107,23 +106,22 @@
 
         ContentResponse getResponse = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid1\", \"jvmPid\" : 1, " +
-                "\"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : " +
-                "\"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\"" +
-                " : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }," +
-                " { \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" :" +
-                " \"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" :" +
-                " \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }," +
-                " { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\"," +
-                " \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }," +
-                " { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\"," +
-                " \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", " +
-                "\"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
-                "\"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid1\",\"jvmPid\":1," +
+                "\"startTime\":1495727607481,\"stopTime\":-9223372036854775808,\"javaVersion\":\"1.8.0_131\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\"," +
+                "\"mainClass\":\"mc\",\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\"," +
+                "\"vmArguments\":\"-Djline.log.jul\\u003dtrue\",\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333," +
+                "\"jvmVersion\":\"25.131-b12\",\"environment\":[{\"key\":\"PATH\",\"value\":" +
+                "\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"},{\"key\":\"XAUTHORITY\",\"value\":" +
+                "\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\",\"value\":\"i3\"}," +
+                "{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"}," +
+                "{\"key\":\"DARWIN_MODE\",\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -141,21 +139,21 @@
 
         ContentResponse getResponse = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid1\", \"jvmPid\" : 1," +
-                " \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" :" +
-                " \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\"" +
-                " : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { " +
-                "\"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", " +
-                "\"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : " +
-                "\"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\"" +
-                " : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : " +
-                "\"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" :" +
-                " \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\"" +
-                " : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000," +
-                " \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid1\",\"jvmPid\":1," +
+                "\"startTime\":1495727607481,\"stopTime\":-9223372036854775808,\"javaVersion\":\"1.8.0_131\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\",\"mainClass\":\"mc\"," +
+                "\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":\"-Djline.log.jul\\u003dtrue\"," +
+                "\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\"," +
+                "\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\",\"value\":\"i3\"}," +
+                "{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"}," +
+                "{\"key\":\"DARWIN_MODE\",\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -170,39 +168,40 @@
         String query = "?limit=2";
         ContentResponse getResponse = client.newRequest(url + query).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid1\", \"jvmPid\" : 1," +
-                " \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" :" +
-                " \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\"," +
-                " \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" " +
-                ": [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, {" +
-                " \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : " +
-                "\"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" :" +
-                " \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { " +
-                "\"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\"" +
-                " : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { " +
-                "\"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\"" +
-                " : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" :" +
-                " \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000, " +
-                "\"username\" : \"user\", \"systemId\" : \"1\" },{ \"agentId\" : \"aid\", \"jvmId\" : \"jid2\", " +
-                "\"jvmPid\" : 2, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { " +
-                "\"$numberLong\" : \"1495727607482\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
-                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" :" +
-                " [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { " +
-                "\"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\"," +
-                " \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" :" +
-                " \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : " +
-                "\"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" : " +
-                "\"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\"" +
-                " }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\"" +
-                " }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000, " +
-                "\"username\" : \"user\", \"systemId\" : \"1\" }] }";
+
+
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid1\",\"jvmPid\":1," +
+                "\"startTime\":1495727607481,\"stopTime\":-9223372036854775808,\"javaVersion\":\"1.8.0_131\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\"," +
+                "\"mainClass\":\"mc\",\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\"," +
+                "\"vmArguments\":\"-Djline.log.jul\\u003dtrue\",\"jvmInfo\":\"mixed mode\"," +
+                "\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\"," +
+                "\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\"," +
+                "\"value\":\"i3\"},{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"}," +
+                "{\"key\":\"DARWIN_MODE\",\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"},{\"agentId\":\"aid\",\"jvmId\":\"jid2\",\"jvmPid\":2," +
+                "\"startTime\":1495727607481,\"stopTime\":1495727607482,\"javaVersion\":\"1.8.0_131\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\",\"mainClass\":\"mc\"," +
+                "\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":\"-Djline.log.jul\\u003dtrue\"," +
+                "\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\",\"environment\":" +
+                "[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"}," +
+                "{\"key\":\"GDMSESSION\",\"value\":\"i3\"},{\"key\":\"fish_greeting\",\"value\":\"\"}," +
+                "{\"key\":\"TERM\",\"value\":\"xterm-256color\"},{\"key\":\"DARWIN_MODE\",\"value\":\"0\"}," +
+                "{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
+
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -217,21 +216,22 @@
         String query = "?offset=1";
         ContentResponse getResponse = client.newRequest(url + query).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid2\", \"jvmPid\" : 2, " +
-                "\"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : " +
-                "\"1495727607482\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\"," +
-                " \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" " +
-                ": [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { " +
-                "\"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\"," +
-                " \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" :" +
-                " \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" " +
-                ": \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" :" +
-                " \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : " +
-                "\"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" :" +
-                " \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000," +
-                " \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid2\",\"jvmPid\":2," +
+                "\"startTime\":1495727607481,\"stopTime\":1495727607482,\"javaVersion\":\"1.8.0_131\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\"," +
+                "\"mainClass\":\"mc\",\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\"," +
+                "\"vmArguments\":\"-Djline.log.jul\\u003dtrue\",\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\"," +
+                "\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"}," +
+                "{\"key\":\"GDMSESSION\",\"value\":\"i3\"},{\"key\":\"fish_greeting\",\"value\":\"\"}," +
+                "{\"key\":\"TERM\",\"value\":\"xterm-256color\"},{\"key\":\"DARWIN_MODE\",\"value\":\"0\"}," +
+                "{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}" +
+                ",{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -246,21 +246,21 @@
         String query = "?query=jvmId==jid2";
         ContentResponse getResponse = client.newRequest(url + query).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid2\", \"jvmPid\" : 2, " +
-                "\"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : " +
-                "\"1495727607482\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\"," +
-                " \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" " +
-                ": [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { " +
-                "\"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\"," +
-                " \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" :" +
-                " \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" " +
-                ": \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" :" +
-                " \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : " +
-                "\"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" :" +
-                " \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000," +
-                " \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid2\",\"jvmPid\":2," +
+                "\"startTime\":1495727607481,\"stopTime\":1495727607482,\"javaVersion\":\"1.8.0_131\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\"," +
+                "\"mainClass\":\"mc\",\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":" +
+                "\"-Djline.log.jul\\u003dtrue\",\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":" +
+                "\"25.131-b12\",\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\",\"value\":\"i3\"}," +
+                "{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"},{\"key\":\"DARWIN_MODE\"," +
+                "\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"},{\"key\":\"DBUS_SESSION_BUS_ADDRESS\"," +
+                "\"value\":\"unix:path\\u003d/run/user/1000/bus\"},{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"}," +
+                "{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"},{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"}," +
+                "{\"key\":\"DISPLAY\",\"value\":\":0\"},{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\"," +
+                "\"value\":\"truecolor\"},{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
+
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -275,7 +275,7 @@
         String query = "?include=agentId,jvmId";
         ContentResponse getResponse = client.newRequest(url + query).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -290,23 +290,21 @@
         String query = "?exclude=agentId";
         ContentResponse getResponse = client.newRequest(url + query).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"jvmId\" : \"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\"" +
-                " : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\"" +
-                " : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\"," +
-                " \"mainClass\" : \"mc\", \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" :" +
-                " \"-Djline.log.jul=true\", \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : " +
-                "\"25.131-b12\", \"environment\" : [{ \"key\" : \"PATH\", \"value\" : " +
-                "\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { \"key\" : \"XAUTHORITY\", \"value\" : " +
-                "\"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" :" +
-                " \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", \"value\" : \"xterm-256color\" }, { " +
-                "\"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, {" +
-                " \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" :" +
-                " \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }," +
-                " { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" :" +
-                " \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" :" +
-                " \"truecolor\" }, { \"key\" : \"_\", \"value\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000, " +
-                "\"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"jvmId\":\"jid1\",\"jvmPid\":1,\"startTime\":1495727607481," +
+                "\"stopTime\":-9223372036854775808,\"javaVersion\":\"1.8.0_131\",\"javaHome\":" +
+                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\",\"mainClass\":\"mc\"," +
+                "\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":\"-Djline.log.jul\\u003dtrue\"," +
+                "\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\",\"environment\":" +
+                "[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\"," +
+                "\"value\":\"i3\"},{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":" +
+                "\"xterm-256color\"},{\"key\":\"DARWIN_MODE\",\"value\":\"0\"},{\"key\":\"LANG\",\"value\":" +
+                "\"en_US.UTF-8\"},{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -323,7 +321,7 @@
 
         ContentResponse getResponse = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [] }";
+        String expected = "{\"response\":[]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -343,23 +341,21 @@
 
         ContentResponse getResponse = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid1\", \"jvmPid\" : 1, " +
-                "\"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : " +
-                "\"-9223372036854775808\" }, \"javaVersion\" : \"1.7.0\", \"javaHome\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"hello\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\"" +
-                " : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, " +
-                "{ \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : " +
-                "\"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : " +
-                "\"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { " +
-                "\"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", " +
-                "\"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, " +
-                "{ \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", " +
-                "\"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\"," +
-                " \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", " +
-                "\"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
-                "\"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid1\",\"jvmPid\":1," +
+                "\"startTime\":1495727607481,\"stopTime\":-9223372036854775808,\"javaVersion\":\"1.7.0\"," +
+                "\"javaHome\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\",\"mainClass\":" +
+                "\"hello\",\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":\"-Djline.log.jul\\u003dtrue\"," +
+                "\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\"," +
+                "\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\"," +
+                "\"value\":\"i3\"},{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"}," +
+                "{\"key\":\"DARWIN_MODE\",\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -388,22 +384,19 @@
 
         ContentResponse getResponse = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid1\", \"jvmPid\" : 1," +
-                " \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : " +
-                "\"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
-                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" :" +
-                " [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { \"key\"" +
-                " : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", " +
-                "\"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" :" +
-                " \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" :" +
-                " \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\"" +
-                " : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" :" +
-                " \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" :" +
-                " \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" :" +
-                " \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000," +
-                " \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid1\",\"jvmPid\":1,\"startTime\":1495727607481," +
+                "\"stopTime\":-9223372036854775808,\"javaVersion\":\"1.8.0_131\",\"javaHome\":" +
+                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\",\"mainClass\":\"mc\"," +
+                "\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":\"-Djline.log.jul\\u003dtrue\"," +
+                "\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\"," +
+                "\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\",\"value\":\"i3\"}," +
+                "{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"},{\"key\":\"DARWIN_MODE\"," +
+                "\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"},{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":" +
+                "\"unix:path\\u003d/run/user/1000/bus\"},{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\"," +
+                "\"value\":\"x11\"},{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"},{\"key\":\"_\",\"value\":" +
+                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}],\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
@@ -421,58 +414,43 @@
 
         ContentResponse getResponse = client.newRequest(url).method(HttpMethod.GET).send();
         assertEquals(200, getResponse.getStatus());
-        String expected = "{ \"response\" : [{ \"agentId\" : \"aid\", \"jvmId\" : \"jid2\", \"jvmPid\" : 2, " +
-                "\"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : " +
-                "\"1495727607482\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\"," +
-                " \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" " +
-                ": [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { " +
-                "\"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\"," +
-                " \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" :" +
-                " \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" " +
-                ": \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" :" +
-                " \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : " +
-                "\"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" :" +
-                " \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000," +
-                " \"username\" : \"user\", \"systemId\" : \"1\" }] }";
+        String expected = "{\"response\":[{\"agentId\":\"aid\",\"jvmId\":\"jid2\",\"jvmPid\":2," +
+                "\"startTime\":1495727607481,\"stopTime\":1495727607482,\"javaVersion\":\"1.8.0_131\",\"javaHome\":" +
+                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\",\"mainClass\":\"mc\"," +
+                "\"javaCommandLine\":\"j cl\",\"jvmName\":\"vm\",\"vmArguments\":\"-Djline.log.jul\\u003dtrue\"," +
+                "\"jvmInfo\":\"mixed mode\",\"lastUpdated\":333,\"jvmVersion\":\"25.131-b12\"," +
+                "\"environment\":[{\"key\":\"PATH\",\"value\":\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\"}," +
+                "{\"key\":\"XAUTHORITY\",\"value\":\"/run/user/1000/gdm/Xauthority\"},{\"key\":\"GDMSESSION\"," +
+                "\"value\":\"i3\"},{\"key\":\"fish_greeting\",\"value\":\"\"},{\"key\":\"TERM\",\"value\":\"xterm-256color\"}," +
+                "{\"key\":\"DARWIN_MODE\",\"value\":\"0\"},{\"key\":\"LANG\",\"value\":\"en_US.UTF-8\"}," +
+                "{\"key\":\"DBUS_SESSION_BUS_ADDRESS\",\"value\":\"unix:path\\u003d/run/user/1000/bus\"}," +
+                "{\"key\":\"XDG_SESSION_ID\",\"value\":\"2\"},{\"key\":\"XDG_SESSION_TYPE\",\"value\":\"x11\"}," +
+                "{\"key\":\"XDG_CURRENT_DESKTOP\",\"value\":\"i3\"},{\"key\":\"DISPLAY\",\"value\":\":0\"}," +
+                "{\"key\":\"CYGWIN_MODE\",\"value\":\"0\"},{\"key\":\"COLORTERM\",\"value\":\"truecolor\"}," +
+                "{\"key\":\"_\",\"value\":\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\"}]," +
+                "\"uid\":1000,\"username\":\"user\",\"systemId\":\"1\"}]}";
         assertEquals(expected, getResponse.getContentAsString());
     }
 
     @Test
-    public void testUpdateTimestamp() throws Exception {
+    public void testUpdateTimestamp() throws InterruptedException, TimeoutException, ExecutionException {
         String updateUrl = jvmsUrl + "/update/systems/1/ts/2000";
         String url = jvmsUrl + "/systems/1";
-        final String body = "[ \"jid1\", \"jid2\" ]";
 
         ContentResponse postResponse = client.newRequest(url).method(HttpMethod.POST)
                 .content(new StringContentProvider(postData), "application/json").send();
         assertEquals(200, postResponse.getStatus());
 
-        // lastUpdate starts out with 333
-        verifyGetIsExpected(url, 333);
 
-        ContentResponse updateResponse = client.newRequest(updateUrl)
-                                               .method(HttpMethod.PUT)
-                                               .content(new StringContentProvider(body))
-                                               .send();
+        ContentResponse updateResponse = client.newRequest(updateUrl).method(HttpMethod.PUT).send();
         assertEquals(200, updateResponse.getStatus());
 
-        // lastUpdate should now be 2000
-        verifyGetIsExpected(url, 2000);
-    }
-
-    private void verifyGetIsExpected(String url, long expectedTs) throws Exception {
         ContentResponse response = client.newRequest(url).method(HttpMethod.GET)
-                .param("include", "lastUpdated").param("limit", "2").send();
+                .param("include", "lastUpdated").send();
         assertEquals(200, response.getStatus());
-        String expected = getExpectedLastUpdateResponse(expectedTs);
+        String expected = "{\"response\":[{\"lastUpdated\":2000}]}";
         assertEquals(expected, response.getContentAsString());
-    }
 
-    private String getExpectedLastUpdateResponse(long expected) {
-        String lastUpdate = "{ \"lastUpdated\" : { \"$numberLong\" : \"" + Long.valueOf(expected).toString() + "\" } }";
-        return "{ \"response\" : [" + lastUpdate + "," + lastUpdate + "] }";
     }
 
     @Test
@@ -487,20 +465,23 @@
         ContentResponse response = client.newRequest(treeUrl).method(HttpMethod.GET).send();
         assertEquals(200, response.getStatus());
         String expected = "{ \"response\" : [{\"systemId\":\"1\", \"jvms\":[{ \"agentId\" : \"aid\", \"jvmId\" : " +
-                "\"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : {" +
-                " \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
-                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" :" +
-                " [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { \"key\"" +
-                " : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\", " +
-                "\"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", " +
-                "\"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : " +
-                "\"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\"" +
-                " : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : " +
-                "\"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : " +
-                "\"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" :" +
-                " \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000," +
-                " \"username\" : \"user\", \"systemId\" : \"1\" }]}]}";
+                "\"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : " +
+                "{ \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
+                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : " +
+                "\"mc\", \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : " +
+                "\"-Djline.log.jul=true\", \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : " +
+                "{ \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" : " +
+                "[{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, " +
+                "{ \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : " +
+                "\"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, " +
+                "{ \"key\" : \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : " +
+                "\"0\" }, { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", " +
+                "\"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, " +
+                "{ \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : " +
+                "\"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, " +
+                "{ \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" : " +
+                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : " +
+                "1000, \"username\" : \"user\", \"systemId\" : \"1\" }]}]}";
         assertEquals(expected, response.getContentAsString());
     }
 
@@ -532,22 +513,23 @@
         String query = "?exclude=systemId";
         ContentResponse response = client.newRequest(treeUrl + query).method(HttpMethod.GET).send();
         assertEquals(200, response.getStatus());
-        String expected = "{ \"response\" : [{\"systemId\":\"1\", \"jvms\":[{ \"agentId\" : \"aid\", \"jvmId\" : " +
-                "\"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : {" +
-                " \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
-                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" : " +
-                "[{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { \"key\" :" +
-                " \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\", \"value\"" +
-                " : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", \"value\" : " +
-                "\"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"LANG\", " +
-                "\"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : " +
-                "\"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" :" +
-                " \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\"" +
-                " }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, " +
-                "{ \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", \"value\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], \"uid\" : 1000, " +
-                "\"username\" : \"user\" }]}]}";
+        String expected = "{ \"response\" : [{\"systemId\":\"1\", \"jvms\":[{ \"agentId\" : \"aid\", " +
+                "\"jvmId\" : \"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, " +
+                "\"stopTime\" : { \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", " +
+                "\"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : " +
+                "\"mc\", \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
+                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, " +
+                "\"jvmVersion\" : \"25.131-b12\", \"environment\" : [{ \"key\" : \"PATH\", \"value\" : " +
+                "\"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { \"key\" : \"XAUTHORITY\", \"value\" : " +
+                "\"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\", \"value\" : \"i3\" }, " +
+                "{ \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", \"value\" : \"xterm-256color\" }, " +
+                "{ \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, " +
+                "{ \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, " +
+                "{ \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, " +
+                "{ \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, " +
+                "{ \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, " +
+                "{ \"key\" : \"_\", \"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
+                "\"uid\" : 1000, \"username\" : \"user\" }]}]}";
         assertEquals(expected, response.getContentAsString());
     }
 
@@ -564,38 +546,36 @@
         ContentResponse response = client.newRequest(treeUrl + query).method(HttpMethod.GET).send();
         assertEquals(200, response.getStatus());
         String expected = "{ \"response\" : [{\"systemId\":\"1\", \"jvms\":[{ \"agentId\" : \"aid\", \"jvmId\" : " +
-                "\"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : {" +
-                " \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" :" +
-                " \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\"" +
-                " : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }," +
-                " { \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : " +
-                "\"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" " +
-                ": \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, {" +
-                " \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", " +
-                "\"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, " +
-                "{ \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", " +
-                "\"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\"," +
-                " \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", " +
-                "\"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
-                "\"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" },{ \"agentId\" : \"aid\", \"jvmId\" " +
-                ": \"jid2\", \"jvmPid\" : 2, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" " +
-                ": { \"$numberLong\" : \"1495727607482\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
+                "\"jid1\", \"jvmPid\" : 1, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : " +
+                "{ \"$numberLong\" : \"-9223372036854775808\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
                 "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\"," +
-                " \"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\"" +
-                " : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }," +
-                " { \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : " +
-                "\"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" " +
-                ": \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }," +
-                " { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", " +
-                "\"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\"" +
-                " }, { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\"," +
-                " \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\"," +
-                " \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\"," +
-                " \"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }]," +
-                " \"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" }]}]}";
+                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
+                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : " +
+                "\"25.131-b12\", \"environment\" : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, " +
+                "{ \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\", \"value\" : \"i3\" }, " +
+                "{ \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", \"value\" : \"xterm-256color\" }, " +
+                "{ \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, " +
+                "{ \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, " +
+                "{ \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, " +
+                "{ \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, " +
+                "{ \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, " +
+                "{ \"key\" : \"_\", \"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
+                "\"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" }," +
+                "{ \"agentId\" : \"aid\", \"jvmId\" : \"jid2\", \"jvmPid\" : 2, \"startTime\" : " +
+                "{ \"$numberLong\" : \"1495727607481\" }, \"stopTime\" : { \"$numberLong\" : \"1495727607482\" }, " +
+                "\"javaVersion\" : \"1.8.0_131\", \"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", " +
+                "\"mainClass\" : \"mc\", \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
+                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\" " +
+                ": [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { \"key\" : \"XAUTHORITY\", " +
+                "\"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : \"GDMSESSION\", \"value\" : \"i3\" }, " +
+                "{ \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\" : \"TERM\", \"value\" : \"xterm-256color\" }, " +
+                "{ \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, " +
+                "{ \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, " +
+                "{ \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, " +
+                "{ \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, " +
+                "{ \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, " +
+                "{ \"key\" : \"_\", \"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
+                "\"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" }]}]}";
         assertEquals(expected, response.getContentAsString());
     }
 
@@ -611,22 +591,25 @@
         String query = "?aliveOnly=false&offset=1";
         ContentResponse response = client.newRequest(treeUrl + query).method(HttpMethod.GET).send();
         assertEquals(200, response.getStatus());
-        String expected = "{ \"response\" : [{\"systemId\":\"1\", \"jvms\":[{ \"agentId\" : \"aid\", \"jvmId\" :" +
-                " \"jid2\", \"jvmPid\" : 2, \"startTime\" : { \"$numberLong\" : \"1495727607481\" }, \"stopTime\" :" +
-                " { \"$numberLong\" : \"1495727607482\" }, \"javaVersion\" : \"1.8.0_131\", \"javaHome\" : " +
-                "\"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", \"mainClass\" : \"mc\", " +
-                "\"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", \"vmArguments\" : \"-Djline.log.jul=true\", " +
-                "\"jvmInfo\" : \"mixed mode\", \"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", \"environment\"" +
-                " : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, { " +
-                "\"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, { \"key\" : " +
-                "\"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, { \"key\"" +
-                " : \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, {" +
-                " \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, { \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", " +
-                "\"value\" : \"unix:path=/run/user/1000/bus\" }, { \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }," +
-                " { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, { \"key\" : \"XDG_CURRENT_DESKTOP\", " +
-                "\"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, { \"key\" : \"CYGWIN_MODE\", " +
-                "\"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, { \"key\" : \"_\", " +
-                "\"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
+        String expected = "{ \"response\" : [{\"systemId\":\"1\", " +
+                "\"jvms\":[{ \"agentId\" : \"aid\", \"jvmId\" : \"jid2\", \"jvmPid\" : 2, " +
+                "\"startTime\" : { \"$numberLong\" : \"1495727607481\" }, " +
+                "\"stopTime\" : { \"$numberLong\" : \"1495727607482\" }, " +
+                "\"javaVersion\" : \"1.8.0_131\", " +
+                "\"javaHome\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre\", " +
+                "\"mainClass\" : \"mc\", \"javaCommandLine\" : \"j cl\", \"jvmName\" : \"vm\", " +
+                "\"vmArguments\" : \"-Djline.log.jul=true\", \"jvmInfo\" : \"mixed mode\", " +
+                "\"lastUpdated\" : { \"$numberLong\" : \"333\" }, \"jvmVersion\" : \"25.131-b12\", " +
+                "\"environment\" : [{ \"key\" : \"PATH\", \"value\" : \"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin\" }, " +
+                "{ \"key\" : \"XAUTHORITY\", \"value\" : \"/run/user/1000/gdm/Xauthority\" }, " +
+                "{ \"key\" : \"GDMSESSION\", \"value\" : \"i3\" }, { \"key\" : \"fish_greeting\", \"value\" : \"\" }, " +
+                "{ \"key\" : \"TERM\", \"value\" : \"xterm-256color\" }, { \"key\" : \"DARWIN_MODE\", \"value\" : \"0\" }, " +
+                "{ \"key\" : \"LANG\", \"value\" : \"en_US.UTF-8\" }, " +
+                "{ \"key\" : \"DBUS_SESSION_BUS_ADDRESS\", \"value\" : \"unix:path=/run/user/1000/bus\" }, " +
+                "{ \"key\" : \"XDG_SESSION_ID\", \"value\" : \"2\" }, { \"key\" : \"XDG_SESSION_TYPE\", \"value\" : \"x11\" }, " +
+                "{ \"key\" : \"XDG_CURRENT_DESKTOP\", \"value\" : \"i3\" }, { \"key\" : \"DISPLAY\", \"value\" : \":0\" }, " +
+                "{ \"key\" : \"CYGWIN_MODE\", \"value\" : \"0\" }, { \"key\" : \"COLORTERM\", \"value\" : \"truecolor\" }, " +
+                "{ \"key\" : \"_\", \"value\" : \"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-1.b12.fc24.x86_64/jre/../bin/java\" }], " +
                 "\"uid\" : 1000, \"username\" : \"user\", \"systemId\" : \"1\" }]}]}";
         assertEquals(expected, response.getContentAsString());
     }
--- a/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/HttpTestUtil.java	Mon Jun 19 17:57:13 2017 +0200
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/HttpTestUtil.java	Tue Jun 20 14:19:38 2017 -0400
@@ -48,7 +48,7 @@
 
 public class HttpTestUtil {
 
-    public static final String EMPTY_RESPONSE = "{ \"response\" : [] }";
+    public static final String EMPTY_RESPONSE = "{\"response\":[]}";
 
     public static void testContentlessResponse(HttpClient client,
                                                HttpMethod httpMethod,