changeset 264:6cabe315cb1f

Add byteman integration services Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025152.html
author Jie Kang <jkang@redhat.com>
date Fri, 22 Sep 2017 10:09:13 -0400
parents 2d35ee835941
children 7b76693bf27d
files common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/servlet/MongoHttpHandlerHelper.java distribution/pom.xml distribution/src/etc/basic-config.properties distribution/src/etc/services.properties services/jvm-byteman/pom.xml services/jvm-byteman/src/main/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanMetricsHttpHandler.java services/jvm-byteman/src/main/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanStatusHttpHandler.java services/jvm-byteman/src/main/java/com/redhat/thermostat/gateway/service/jvm/byteman/SwaggerSpecResourceHandler.java services/jvm-byteman/src/main/resources/jvm-byteman-swagger.yaml services/jvm-byteman/src/main/webapp/WEB-INF/web.xml services/pom.xml tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanMetricsServiceIntegrationTest.java tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanServiceIntegrationTest.java tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanStatusServiceIntegrationTest.java
diffstat 14 files changed, 993 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/servlet/MongoHttpHandlerHelper.java	Thu Sep 21 10:08:21 2017 -0400
+++ b/common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/servlet/MongoHttpHandlerHelper.java	Fri Sep 22 10:09:13 2017 -0400
@@ -36,10 +36,24 @@
 
 package com.redhat.thermostat.gateway.common.mongodb.servlet;
 
+import static com.redhat.thermostat.gateway.common.util.ServiceException.CANNOT_QUERY_REALMS_PROPERTY;
+import static com.redhat.thermostat.gateway.common.util.ServiceException.DATABASE_UNAVAILABLE;
+import static com.redhat.thermostat.gateway.common.util.ServiceException.EXPECTED_JSON_ARRAY;
+import static com.redhat.thermostat.gateway.common.util.ServiceException.MALFORMED_CLIENT_REQUEST;
+import static com.redhat.thermostat.gateway.common.util.ServiceException.UNEXPECTED_ERROR;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response;
+
+import org.bson.json.JsonParseException;
+
 import com.mongodb.DBObject;
 import com.mongodb.MongoTimeoutException;
 import com.mongodb.MongoWriteException;
-
 import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
 import com.redhat.thermostat.gateway.common.mongodb.ThermostatFields;
 import com.redhat.thermostat.gateway.common.mongodb.ThermostatMongoStorage;
@@ -49,19 +63,6 @@
 import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataResponseBuilder;
 import com.redhat.thermostat.gateway.common.mongodb.response.MongoResponseBuilder;
 import com.redhat.thermostat.gateway.common.util.HttpResponseExceptionHandler;
-import org.bson.json.JsonParseException;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.Response;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-
-import static com.redhat.thermostat.gateway.common.util.ServiceException.CANNOT_QUERY_REALMS_PROPERTY;
-import static com.redhat.thermostat.gateway.common.util.ServiceException.DATABASE_UNAVAILABLE;
-import static com.redhat.thermostat.gateway.common.util.ServiceException.EXPECTED_JSON_ARRAY;
-import static com.redhat.thermostat.gateway.common.util.ServiceException.MALFORMED_CLIENT_REQUEST;
-import static com.redhat.thermostat.gateway.common.util.ServiceException.UNEXPECTED_ERROR;
 
 public class MongoHttpHandlerHelper {
 
@@ -105,7 +106,7 @@
 
     /*
      * originalQueries contains only query info from the client's original request argument. queries contains this info,
-     * as well as added JVM/SYS ids built by andSystemIdJvmIdQuery(...). 
+     * as well as added JVM/SYS ids built by andSystemIdJvmIdQuery(...).
      */
     public Response handleGet(HttpServletRequest httpServletRequest, ServletContext context, int limit, int offset,
                               String sort, String queries, String includes, String excludes, boolean returnMetadata,
--- a/distribution/pom.xml	Thu Sep 21 10:08:21 2017 -0400
+++ b/distribution/pom.xml	Fri Sep 22 10:09:13 2017 -0400
@@ -223,6 +223,13 @@
                         </artifactItem>
                         <artifactItem>
                             <groupId>com.redhat.thermostat</groupId>
+                            <artifactId>thermostat-web-gateway-service-jvm-byteman</artifactId>
+                            <version>${project.version}</version>
+                            <type>war</type>
+                            <overWrite>false</overWrite>
+                        </artifactItem>
+                        <artifactItem>
+                            <groupId>com.redhat.thermostat</groupId>
                             <artifactId>thermostat-web-gateway-service-jvm-cpu</artifactId>
                             <version>${project.version}</version>
                             <type>war</type>
@@ -305,6 +312,20 @@
         </dependency>
         <dependency>
             <groupId>com.redhat.thermostat</groupId>
+            <artifactId>thermostat-web-gateway-service-jvm-byteman</artifactId>
+            <version>${project.version}</version>
+            <type>war</type>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.redhat.thermostat</groupId>
+            <artifactId>thermostat-web-gateway-service-jvm-cpu</artifactId>
+            <version>${project.version}</version>
+            <type>war</type>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.redhat.thermostat</groupId>
             <artifactId>thermostat-web-gateway-service-jvm-gc</artifactId>
             <version>${project.version}</version>
             <type>war</type>
@@ -312,7 +333,7 @@
         </dependency>
         <dependency>
             <groupId>com.redhat.thermostat</groupId>
-            <artifactId>thermostat-web-gateway-service-jvms</artifactId>
+            <artifactId>thermostat-web-gateway-service-jvm-io</artifactId>
             <version>${project.version}</version>
             <type>war</type>
             <scope>provided</scope>
@@ -326,14 +347,7 @@
         </dependency>
         <dependency>
             <groupId>com.redhat.thermostat</groupId>
-            <artifactId>thermostat-web-gateway-service-jvm-io</artifactId>
-            <version>${project.version}</version>
-            <type>war</type>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.redhat.thermostat</groupId>
-            <artifactId>thermostat-web-gateway-service-jvm-cpu</artifactId>
+            <artifactId>thermostat-web-gateway-service-jvms</artifactId>
             <version>${project.version}</version>
             <type>war</type>
             <scope>provided</scope>
--- a/distribution/src/etc/basic-config.properties	Thu Sep 21 10:08:21 2017 -0400
+++ b/distribution/src/etc/basic-config.properties	Fri Sep 22 10:09:13 2017 -0400
@@ -1,2 +1,2 @@
 agent=agent-pwd,r-thermostat,w-thermostat,u-thermostat,d-thermostat,receiver_provider-commands,thermostat
-client=client-pwd,r-thermostat,kill_vm-commands,ping-commands,thermostat
\ No newline at end of file
+client=client-pwd,r-thermostat,kill_vm-commands,ping-commands,thermostat,byteman-commands
\ No newline at end of file
--- a/distribution/src/etc/services.properties	Thu Sep 21 10:08:21 2017 -0400
+++ b/distribution/src/etc/services.properties	Fri Sep 22 10:09:13 2017 -0400
@@ -1,4 +1,5 @@
 /commands = thermostat-web-gateway-service-commands-@project.version@.war
+/jvm-byteman = thermostat-web-gateway-service-jvm-byteman-@project.version@.war
 /jvm-cpu = thermostat-web-gateway-service-jvm-cpu-@project.version@.war
 /jvm-compiler = thermostat-web-gateway-service-jvm-compiler-@project.version@.war
 /jvm-gc = thermostat-web-gateway-service-jvm-gc-@project.version@.war
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/jvm-byteman/pom.xml	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,96 @@
+<!--
+
+ Copyright 2012-2017 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses/>.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>thermostat-web-gateway-services</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>1.99.12-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-web-gateway-service-jvm-byteman</artifactId>
+
+  <packaging>war</packaging>
+
+  <name>Thermostat Web Gateway JVM Byteman Service</name>
+  
+  <properties>
+    <com.redhat.thermostat.gateway.SERVICE_NAME>jvm-byteman</com.redhat.thermostat.gateway.SERVICE_NAME>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-war-plugin</artifactId>
+          <configuration>
+          <webResources>
+            <resource>
+              <directory>src/main/webapp</directory>
+              <filtering>true</filtering>
+            </resource>
+          </webResources>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <!-- Thermostat Web Gateway Dependencies -->
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-gateway-common-mongodb</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <!-- Servlet API deps -->
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <version>${javax.servlet.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- JAX-RS Dependencies -->
+    <dependency>
+      <groupId>javax.ws.rs</groupId>
+      <artifactId>javax.ws.rs-api</artifactId>
+      <version>${javax-rs-api.version}</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/jvm-byteman/src/main/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanMetricsHttpHandler.java	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,93 @@
+/*
+ * 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.service.jvm.byteman;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+
+import com.redhat.thermostat.gateway.common.core.model.OffsetParameter;
+import com.redhat.thermostat.gateway.common.mongodb.servlet.MongoHttpHandlerHelper;
+import com.redhat.thermostat.gateway.common.mongodb.servlet.RequestParameters;
+
+@Path("/metrics")
+public class JvmBytemanMetricsHttpHandler {
+
+    private static final String NO_SYSTEM_ID = null;
+    private static final String BYTEMAN_METRICS_COLLECTION_NAME = "jvm-byteman-metrics";
+    private final MongoHttpHandlerHelper metricsServiceHelper = new MongoHttpHandlerHelper( BYTEMAN_METRICS_COLLECTION_NAME );
+
+    @GET
+    @Path("/jvms/{" + RequestParameters.JVM_ID +"}")
+    @Consumes({ "application/json" })
+    @Produces({ "application/json; charset=utf-8" })
+    public Response getJvmBytemanMetrics(@PathParam(RequestParameters.JVM_ID) String jvmId,
+                                         @QueryParam(RequestParameters.LIMIT) @DefaultValue("1") Integer limit,
+                                         @QueryParam(RequestParameters.OFFSET) @DefaultValue("0") OffsetParameter offsetParam,
+                                         @QueryParam(RequestParameters.SORT) String sort,
+                                         @QueryParam(RequestParameters.QUERY) String queries,
+                                         @QueryParam(RequestParameters.INCLUDE) String includes,
+                                         @QueryParam(RequestParameters.EXCLUDE) String excludes,
+                                         @QueryParam(RequestParameters.METADATA) @DefaultValue("false") Boolean metadata,
+                                         @Context ServletContext context,
+                                         @Context HttpServletRequest httpServletRequest) {
+        return metricsServiceHelper.handleGetWithJvmID(httpServletRequest, context, NO_SYSTEM_ID, jvmId, limit, offsetParam.getValue(), sort, queries, includes, excludes, metadata);
+    }
+
+    @POST
+    @Path("/systems/{" + RequestParameters.SYSTEM_ID +"}/jvms/{" + RequestParameters.JVM_ID +"}")
+    @Consumes({ "application/json" })
+    @Produces({ "application/json; charset=utf-8" })
+    public Response createJvmBytemanMetrics(String body,
+                                            @PathParam(RequestParameters.SYSTEM_ID) String systemId,
+                                            @PathParam(RequestParameters.JVM_ID) String jvmId,
+                                            @QueryParam(RequestParameters.METADATA) @DefaultValue("false") Boolean metadata,
+                                            @Context ServletContext context,
+                                            @Context HttpServletRequest httpServletRequest) {
+        return metricsServiceHelper.handlePostWithJvmID(httpServletRequest, context, systemId, jvmId, metadata, body);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/jvm-byteman/src/main/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanStatusHttpHandler.java	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,92 @@
+/*
+ * 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.service.jvm.byteman;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+
+import com.redhat.thermostat.gateway.common.mongodb.servlet.MongoHttpHandlerHelper;
+import com.redhat.thermostat.gateway.common.mongodb.servlet.RequestParameters;
+
+@Path("/status")
+public class JvmBytemanStatusHttpHandler {
+    private static final String BYTEMAN_STATUS_COLLECTION_NAME = "jvm-byteman-status";
+    private static final int LIMIT_ONE = 1;
+    private static final int OFFSET_ZERO = 0;
+    private static final String DESCENDING_TIMESTAMP_SORT = "-timeStamp";
+    private static final String NO_QUERIES = null;
+    private static final String NO_SYSTEM_ID = null;
+    private final MongoHttpHandlerHelper statusServiceHelper = new MongoHttpHandlerHelper( BYTEMAN_STATUS_COLLECTION_NAME );
+
+    @GET
+    @Path("/jvms/{" + RequestParameters.JVM_ID +"}")
+    @Consumes({ "application/json" })
+    @Produces({ "application/json; charset=utf-8" })
+    public Response getJvmBytemanStatus(@PathParam(RequestParameters.JVM_ID) String jvmId,
+                                        @QueryParam(RequestParameters.INCLUDE) String includes,
+                                        @QueryParam(RequestParameters.EXCLUDE) String excludes,
+                                        @QueryParam(RequestParameters.METADATA) @DefaultValue("false") Boolean metadata,
+                                        @Context ServletContext context,
+                                        @Context HttpServletRequest httpServletRequest) {
+        return statusServiceHelper.handleGetWithJvmID(httpServletRequest, context, NO_SYSTEM_ID, jvmId, LIMIT_ONE, OFFSET_ZERO, DESCENDING_TIMESTAMP_SORT, NO_QUERIES, includes, excludes, metadata);
+    }
+
+    @POST
+    @Path("/systems/{" + RequestParameters.SYSTEM_ID +"}/jvms/{" + RequestParameters.JVM_ID +"}")
+    @Consumes({ "application/json" })
+    @Produces({ "application/json; charset=utf-8" })
+    public Response createJvmBytemanStatus(String body,
+                                           @PathParam(RequestParameters.SYSTEM_ID) String systemId,
+                                           @PathParam(RequestParameters.JVM_ID) String jvmId,
+                                           @QueryParam(RequestParameters.METADATA) @DefaultValue("false") Boolean metadata,
+                                           @Context ServletContext context,
+                                           @Context HttpServletRequest httpServletRequest) {
+        return statusServiceHelper.handlePostWithJvmID(httpServletRequest, context, systemId, jvmId, metadata, body);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/jvm-byteman/src/main/java/com/redhat/thermostat/gateway/service/jvm/byteman/SwaggerSpecResourceHandler.java	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,59 @@
+/*
+ * 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.service.jvm.byteman;
+
+import java.io.IOException;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import com.redhat.thermostat.gateway.common.core.servlet.BasicResourceHandler;
+
+@Path("doc/{fileName: .+\\.yaml}")
+@Produces(MediaType.TEXT_PLAIN)
+public class SwaggerSpecResourceHandler extends BasicResourceHandler {
+
+    @GET
+    public Response getFileAsPlainText(@PathParam("fileName") String fileName) throws IOException {
+        return getFileAsResponse(SwaggerSpecResourceHandler.class.getClassLoader(), fileName);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/jvm-byteman/src/main/resources/jvm-byteman-swagger.yaml	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,271 @@
+swagger: '2.0'
+info:
+  version: 0.0.1
+  title: Thermostat Web Gateway JVM Byteman API
+  license:
+    name: GPL v2 with Classpath Exception
+    url: 'http://www.gnu.org/licenses'
+consumes:
+  - application/json
+produces:
+  - application/json
+basePath: /jvm-byteman/0.0.1
+paths:
+  /status/jvms/{jvmId}:
+    parameters:
+      - $ref: '#/parameters/thermostat-realms'
+      - $ref: '#/parameters/jvm-id'
+    get:
+      description: Get the latest Byteman status.
+      parameters:
+        - $ref: '#/parameters/include'
+        - $ref: '#/parameters/exclude'
+        - $ref: '#/parameters/metadata'
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/jvm-byteman-status-response'
+  /status/systems/{systemId}/jvms/{jvmId}:
+    parameters:
+      - $ref: '#/parameters/thermostat-realms'
+      - $ref: '#/parameters/system-id'
+      - $ref: '#/parameters/jvm-id'
+    post:
+      description: Add a Byteman status.
+      parameters:
+        - $ref: '#/parameters/jvm-byteman-status'
+        - $ref: '#/parameters/metadata'
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/metadata'
+  /metrics/jvms/{jvmId}:
+    parameters:
+      - $ref: '#/parameters/thermostat-realms'
+      - $ref: '#/parameters/jvm-id'
+    get:
+      description: Get Byteman metrics.
+      parameters:
+        - $ref: '#/parameters/limit'
+        - $ref: '#/parameters/offset'
+        - $ref: '#/parameters/sort'
+        - $ref: '#/parameters/include'
+        - $ref: '#/parameters/exclude'
+        - $ref: '#/parameters/query'
+        - $ref: '#/parameters/metadata'
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/jvm-byteman-metrics-response'
+  /metrics/systems/{systemId}/jvms/{jvmId}:
+    parameters:
+      - $ref: '#/parameters/thermostat-realms'
+      - $ref: '#/parameters/system-id'
+      - $ref: '#/parameters/jvm-id'
+    post:
+      description: Add Byteman metrics.
+      parameters:
+        - $ref: '#/parameters/jvm-byteman-metrics-array'
+        - $ref: '#/parameters/metadata'
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/metadata'
+definitions:
+  jvm-byteman-metrics-response:
+    type: object
+    properties:
+      response:
+          $ref: '#/definitions/jvm-byteman-metrics-array'
+      metadata:
+        $ref: '#/definitions/metadata'
+  jvm-byteman-status-response:
+    type: object
+    properties:
+      response:
+          $ref: '#/definitions/jvm-byteman-status-array'
+      metadata:
+        $ref: '#/definitions/metadata'
+  jvm-byteman-status-array:
+    type: array
+    items:
+      $ref: '#/definitions/jvm-byteman-status'
+  jvm-byteman-metrics-array:
+    type: array
+    items:
+      $ref: '#/definitions/jvm-byteman-metric'
+  jvm-byteman-metric:
+    type: object
+    properties:
+      agentId:
+        type: string
+      jvmId:
+        type: string
+      timeStamp:
+        $ref: '#/definitions/timestamp'
+      marker:
+        type: string
+      payload:
+        $ref: '#/definitions/jvm-byteman-metric-payload'
+  jvm-byteman-status:
+    type: object
+    properties:
+      agentId:
+        type: string
+      jvmId:
+        type: string
+      timeStamp:
+        $ref: '#/definitions/timestamp'
+      rule:
+        type: string
+      listenPort:
+        type: integer
+  jvm-byteman-metric-payload:
+    type: object
+    description: "A key-value pair, where values can be of type String, Boolean or Double. Example { \"some-key\": \"stringValue\", \"booleanKey\" : true, \"doubleKey\": 3.14 }"
+    properties:
+      key:
+        type: string
+      value:
+        $ref: '#/definitions/map-value'
+  map-value:
+    enum: [
+      $ref: '#/definitions/map-value-string',
+      $ref: '#/definitions/map-value-boolean',
+      $ref: '#/definitions/map-value-float'
+    ]
+  map-value-string:
+    type: string
+  map-value-boolean:
+    type: boolean
+  map-value-float:
+    type: number
+    format: float
+  metadata:
+      type: object
+      properties:
+        payloadCount:
+          type: integer
+        count:
+          type: integer
+        prev:
+          type: string
+        next:
+          type: string
+        first:
+          type: string
+        last:
+          type: string
+        insertCount:
+          type: integer
+        matchCount:
+          type: integer
+        elapsed:
+          type: integer
+          format: int64
+  timestamp:
+    description: UNIX timestamp in milliseconds
+    type: object
+    properties:
+      $numberLong:
+        type: string
+  put-body:
+    type: object
+    properties:
+      "set":
+        type: object
+parameters:
+  system-id:
+    name: systemId
+    in: path
+    required: true
+    type: string
+  jvm-id:
+    name: jvmId
+    in: path
+    required: true
+    type: string
+  jvm-byteman-status:
+    name: jvm-byteman-status
+    in: body
+    description: The jvm byteman status
+    required: true
+    schema:
+      $ref: '#/definitions/jvm-byteman-status-array'
+  jvm-byteman-status-array:
+    name: jvm-byteman-status-array
+    in: body
+    description: The jvm byteman status
+    required: true
+    schema:
+      $ref: '#/definitions/jvm-byteman-status-array'
+  jvm-byteman-metrics-array:
+    name: jvm-byteman-metrics-array
+    in: body
+    description: The jvm Byteman metrics
+    required: true
+    schema:
+      $ref: '#/definitions/jvm-byteman-metrics-array'
+  put-body:
+    name: putBody
+    in: body
+    description: "The JSON object containing a 'set' object. This contains single item JSON objects that specify the field to replace and the JSON value to replace with. Example { \"set\" : { \"field\" : \"value\", \"field2\":{\"object\":\"item\"} }"
+    required: true
+    schema:
+      $ref: '#/definitions/put-body'
+  limit:
+    name: limit
+    in: query
+    description: Limit of items to return. Example '1'
+    type: integer
+  offset:
+    name: offset
+    in: query
+    description: Offset of items to return. Example '0'
+    type: integer
+  sort:
+    name: sort
+    in: query
+    description: Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?s=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.
+    type: string
+  query:
+    name: query
+    in: query
+    description: Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?q=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.
+    type: string
+  include:
+    name: include
+    in: query
+    description: >-
+      Inclusion string. Comma separated list of fields to include in the
+      response. Example '?include=a,b' Fields use dot notation for embedded
+      documents. Example 'outer.inner' refers to field inner contained in field
+      outer. Cannot be used in combination with 'exclude' parameter. Overriden by
+      'exclude' parameter
+    type: string
+    required: false
+  exclude:
+    name: exclude
+    in: query
+    description: >-
+      Exclusion string. Comma separated list of fields to exclude in the
+      response. Example '?exclude=a,b' Fields use dot notation for embedded
+      documents. Example 'outer.inner' refers to field inner contained in field
+      outer. Cannot be used in combination with 'include' parameter; takes
+      precedence over 'include' parameter
+    type: string
+    required: false
+  metadata:
+    name: metadata
+    type: boolean
+    in: query
+    description: "Metadata flag. If set to 'true', the subsequent request response will return metadata information. If set to 'false', such metadata information will be omitted."
+  thermostat-realms:
+      name: X-Thermostat-Realms
+      type: string
+      in: header
+      description: "Realms Header used to specify a subset of roles to use for Keycloak authorization. Attempts to specify realms that the client does not have, or no valid realms at all will result in a 400 Bad Request response. Expects a space separated list of realms. Example 'X-Thermostat-Realms: realm-one realm-two'"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/services/jvm-byteman/src/main/webapp/WEB-INF/web.xml	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,88 @@
+<!--
+
+ 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.
+
+-->
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+         version="3.1">
+    <servlet>
+        <servlet-name>JvmBytemanServlet</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>
+                jersey.config.server.provider.packages
+            </param-name>
+            <param-value>
+                com.redhat.thermostat.gateway.service.jvm.byteman,
+            </param-value>
+        </init-param>
+    </servlet>
+    <filter>
+        <filter-name>ServiceVersionFilter</filter-name>
+        <filter-class>com.redhat.thermostat.gateway.common.core.servlet.ServiceVersionFilter</filter-class>
+        <init-param>
+            <param-name>version</param-name>
+            <param-value>0.0.1</param-value>
+        </init-param>
+    </filter>
+    <filter-mapping>
+        <filter-name>ServiceVersionFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+    <servlet-mapping>
+        <servlet-name>JvmBytemanServlet</servlet-name>
+        <url-pattern>/0.0.1/*</url-pattern>
+    </servlet-mapping>
+    <!-- Service configuration -->
+    <context-param>
+        <param-name>com.redhat.thermostat.gateway.SERVICE_NAME</param-name>
+        <param-value>@com.redhat.thermostat.gateway.SERVICE_NAME@</param-value>
+    </context-param>
+    <!-- Listener for setting up the storage connection -->
+    <listener>
+        <listener-class>com.redhat.thermostat.gateway.common.mongodb.servlet.StorageConnectionSettingListener</listener-class>
+    </listener>
+    <!-- Allow viewing of API spec without authentication -->
+    <security-constraint>
+      <web-resource-collection>
+        <web-resource-name>Swagger API Spec File</web-resource-name>
+        <url-pattern>/0.0.1/doc/@com.redhat.thermostat.gateway.SERVICE_NAME@-swagger.yaml</url-pattern>
+      </web-resource-collection>
+      <!-- Explicitly no auth constraint for this file -->
+    </security-constraint>
+</web-app>
--- a/services/pom.xml	Thu Sep 21 10:08:21 2017 -0400
+++ b/services/pom.xml	Fri Sep 22 10:09:13 2017 -0400
@@ -52,10 +52,11 @@
 
     <modules>
         <module>commands</module>
+        <module>jvms</module>
+        <module>jvm-byteman</module>
+        <module>jvm-cpu</module>
         <module>jvm-gc</module>
-        <module>jvms</module>
         <module>jvm-memory</module>
-        <module>jvm-cpu</module>
         <module>jvm-io</module>
         <module>jvm-compiler</module>
         <module>systems</module>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanMetricsServiceIntegrationTest.java	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,102 @@
+/*
+ * 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.service.jvm.byteman;
+
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Test;
+
+import com.redhat.thermostat.gateway.tests.utils.HttpTestUtil;
+
+/**
+ * Integration tests for {@code jvm-byteman/<version>/metrics/*} URLs
+ *
+ */
+public class JvmBytemanMetricsServiceIntegrationTest extends JvmBytemanServiceIntegrationTest {
+
+    private static final String COLLECTION_NAME = "jvm-byteman-metrics";
+    private static final String SYSTEM_ID = UUID.randomUUID().toString();
+    private static final String JVM_ID = UUID.randomUUID().toString();
+    private static final String STATUS_BASE_URL = baseUrl + "/" + SERVICE_NAME + "/" + VERSION_NUMBER + "/" + "metrics";
+    private static final String SERVICE_URL_SYSTEM_JVM = STATUS_BASE_URL + "/systems/" + SYSTEM_ID + "/jvms/" + JVM_ID;
+    private static final String SERVICE_URL_JVM = STATUS_BASE_URL + "/jvms/" + JVM_ID;
+
+    public JvmBytemanMetricsServiceIntegrationTest() {
+        super("ignored", COLLECTION_NAME);
+    }
+
+    @Test
+    public void testGetForJvms() throws InterruptedException, TimeoutException, ExecutionException {
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, SERVICE_URL_JVM, HttpStatus.OK_200, HttpTestUtil.EMPTY_RESPONSE);
+    }
+
+    @Test
+    public void testPost() throws InterruptedException, TimeoutException, ExecutionException {
+        String expected = "{\"response\":[{\"a\":\"b\",\"systemId\":\"" + SYSTEM_ID + "\",\"jvmId\":\"" + JVM_ID + "\"}]}";
+        HttpTestUtil.addRecords(client, SERVICE_URL_SYSTEM_JVM, "[{\"a\":\"b\"}]");
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, SERVICE_URL_JVM, HttpStatus.OK_200, expected);
+    }
+
+    /**
+     * Verifies that PUT is not an allowed HTTP method.
+     *
+     * @throws InterruptedException
+     * @throws TimeoutException
+     * @throws ExecutionException
+     */
+    @Test
+    public void testPut() throws InterruptedException, TimeoutException, ExecutionException {
+        String putPayload = "any String, ignore me";
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, SERVICE_URL_SYSTEM_JVM, putPayload, HttpStatus.METHOD_NOT_ALLOWED_405);
+    }
+
+    /**
+     * Verifies DELETE is not an allowed HTTP method.
+     *
+     * @throws InterruptedException
+     * @throws TimeoutException
+     * @throws ExecutionException
+     */
+    @Test
+    public void testDelete() throws InterruptedException, TimeoutException, ExecutionException {
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.DELETE, SERVICE_URL_SYSTEM_JVM, HttpStatus.METHOD_NOT_ALLOWED_405);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanServiceIntegrationTest.java	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,60 @@
+/*
+ * 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.service.jvm.byteman;
+
+import com.redhat.thermostat.gateway.tests.integration.MongoIntegrationTest;
+
+public abstract class JvmBytemanServiceIntegrationTest extends MongoIntegrationTest {
+
+    protected static final String SERVICE_NAME = "jvm-byteman";
+    protected static final String VERSION_NUMBER = "0.0.1";
+
+    public JvmBytemanServiceIntegrationTest(String serviceUrl, String collectionName) {
+        super(serviceUrl, collectionName);
+    }
+
+    @Override
+    public String getServiceVersion() {
+        return VERSION_NUMBER;
+    }
+
+    @Override
+    public String getServiceName() {
+        return SERVICE_NAME;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/byteman/JvmBytemanStatusServiceIntegrationTest.java	Fri Sep 22 10:09:13 2017 -0400
@@ -0,0 +1,88 @@
+/*
+ * 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.service.jvm.byteman;
+
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Test;
+
+import com.redhat.thermostat.gateway.tests.utils.HttpTestUtil;
+
+/**
+ * Integration tests for {@code jvm-byteman/<version>/status/*} URLs
+ *
+ */
+public class JvmBytemanStatusServiceIntegrationTest extends JvmBytemanServiceIntegrationTest {
+
+    private static final String COLLECTION_NAME = "jvm-byteman-status";
+    private static final String SYSTEM_ID = UUID.randomUUID().toString();
+    private static final String JVM_ID = UUID.randomUUID().toString();
+    private static final String STATUS_BASE_URL = baseUrl + "/" + SERVICE_NAME + "/" + VERSION_NUMBER + "/" + "status";
+    private static final String SERVICE_URL_SYSTEM_JVM = STATUS_BASE_URL + "/systems/" + SYSTEM_ID + "/jvms/" + JVM_ID;
+    private static final String SERVICE_URL_JVM = STATUS_BASE_URL + "/jvms/" + JVM_ID;
+
+    public JvmBytemanStatusServiceIntegrationTest() {
+        super("ignored", COLLECTION_NAME);
+    }
+
+    @Test
+    public void testGetForJvms() throws InterruptedException, TimeoutException, ExecutionException {
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, SERVICE_URL_JVM, HttpStatus.OK_200, HttpTestUtil.EMPTY_RESPONSE);
+    }
+
+    @Test
+    public void testPost() throws InterruptedException, TimeoutException, ExecutionException {
+        String expected = "{\"response\":[{\"a\":\"b\",\"systemId\":\"" + SYSTEM_ID + "\",\"jvmId\":\"" + JVM_ID + "\"}]}";
+        HttpTestUtil.addRecords(client, SERVICE_URL_SYSTEM_JVM, "[{\"a\":\"b\"}]");
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.GET, SERVICE_URL_JVM, HttpStatus.OK_200, expected);
+    }
+
+    @Test
+    public void testPut() throws InterruptedException, TimeoutException, ExecutionException {
+        String putContent = "{\"set\": {\"a\":\"c\"}}";
+        HttpTestUtil.testContentResponse(client, HttpMethod.PUT, SERVICE_URL_SYSTEM_JVM, putContent, HttpStatus.METHOD_NOT_ALLOWED_405);
+    }
+
+    @Test
+    public void testDelete() throws InterruptedException, TimeoutException, ExecutionException {
+        HttpTestUtil.testContentlessResponse(client, HttpMethod.DELETE, SERVICE_URL_SYSTEM_JVM + "?q=a==b", HttpStatus.METHOD_NOT_ALLOWED_405);
+    }
+}