accumulo-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] milleruntime closed pull request #289: ACCUMULO-4677 Sanitizing PathParam values in REST-based Monitor
Date Thu, 01 Jan 1970 00:00:00 GMT
milleruntime closed pull request #289: ACCUMULO-4677 Sanitizing PathParam values in REST-based Monitor
URL: https://github.com/apache/accumulo/pull/289
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/assemble/pom.xml b/assemble/pom.xml
index 2cf4d7aee0..4167de3d83 100644
--- a/assemble/pom.xml
+++ b/assemble/pom.xml
@@ -32,6 +32,10 @@
       <artifactId>jcommander</artifactId>
       <optional>true</optional>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml</groupId>
+      <artifactId>classmate</artifactId>
+    </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
@@ -79,6 +83,10 @@
       <groupId>javax.annotation</groupId>
       <artifactId>javax.annotation-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>javax.el</groupId>
+      <artifactId>javax.el-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
@@ -283,6 +291,10 @@
       <groupId>org.glassfish.jersey.core</groupId>
       <artifactId>jersey-server</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.glassfish.jersey.ext</groupId>
+      <artifactId>jersey-bean-validation</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.glassfish.jersey.ext</groupId>
       <artifactId>jersey-entity-filtering</artifactId>
@@ -303,10 +315,26 @@
       <groupId>org.glassfish.jersey.media</groupId>
       <artifactId>jersey-media-json-jackson</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.glassfish.web</groupId>
+      <artifactId>el-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.glassfish.web</groupId>
+      <artifactId>javax.el</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-validator</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.javassist</groupId>
       <artifactId>javassist</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.jboss.logging</groupId>
+      <artifactId>jboss-logging</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
diff --git a/assemble/src/main/assemblies/component.xml b/assemble/src/main/assemblies/component.xml
index 470b5f7578..405b7b3449 100644
--- a/assemble/src/main/assemblies/component.xml
+++ b/assemble/src/main/assemblies/component.xml
@@ -52,6 +52,7 @@
         <include>org.slf4j:slf4j-api</include>
         <include>org.slf4j:slf4j-log4j12</include>
         <!-- Jersey/Jackson-based webservice -->
+        <include>com.fasterxml:classmate</include>
         <include>com.fasterxml.jackson.core:jackson-annotations</include>
         <include>com.fasterxml.jackson.core:jackson-core</include>
         <include>com.fasterxml.jackson.core:jackson-databind</include>
@@ -59,6 +60,7 @@
         <include>com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider</include>
         <include>com.fasterxml.jackson.module:jackson-module-jaxb-annotations</include>
         <include>javax.annotation:javax.annotation-api</include>
+        <include>javax.el:javax.el-api</include>
         <include>javax.validation:validation-api</include>
         <include>javax.ws.rs:javax.ws.rs-api</include>
         <include>org.freemarker:freemarker</include>
@@ -75,12 +77,17 @@
         <include>org.glassfish.jersey.core:jersey-client</include>
         <include>org.glassfish.jersey.core:jersey-common</include>
         <include>org.glassfish.jersey.core:jersey-server</include>
+        <include>org.glassfish.jersey.ext:jersey-bean-validation</include>
         <include>org.glassfish.jersey.ext:jersey-entity-filtering</include>
         <include>org.glassfish.jersey.ext:jersey-mvc-freemarker</include>
         <include>org.glassfish.jersey.ext:jersey-mvc</include>
         <include>org.glassfish.jersey.media:jersey-media-jaxb</include>
         <include>org.glassfish.jersey.media:jersey-media-json-jackson</include>
+        <include>org.glassfish.web:javax.el</include>
+        <include>org.glassfish.web:el-impl</include>
+        <include>org.hibernate:hibernate-validator</include>
         <include>org.javassist:javassist</include>
+        <include>org.jboss.logging:jboss-logging</include>
         <include>log4j:log4j</include>
       </includes>
     </dependencySet>
diff --git a/pom.xml b/pom.xml
index 49ce9d8687..4cce01242f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,6 +133,7 @@
     <httpclient.version>4.3.1</httpclient.version>
     <it.failIfNoSpecifiedTests>false</it.failIfNoSpecifiedTests>
     <jackson.version>2.9.0</jackson.version>
+    <javax.el.version>2.2.4</javax.el.version>
     <jersey.version>2.25.1</jersey.version>
     <jetty.version>9.3.21.v20170918</jetty.version>
     <maven.compiler.source>1.8</maven.compiler.source>
@@ -162,6 +163,11 @@
         <artifactId>jcommander</artifactId>
         <version>1.72</version>
       </dependency>
+      <dependency>
+        <groupId>com.fasterxml</groupId>
+        <artifactId>classmate</artifactId>
+        <version>1.0.0</version>
+      </dependency>
       <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-annotations</artifactId>
@@ -259,6 +265,11 @@
         <artifactId>javax.annotation-api</artifactId>
         <version>1.2</version>
       </dependency>
+      <dependency>
+        <groupId>javax.el</groupId>
+        <artifactId>javax.el-api</artifactId>
+        <version>${javax.el.version}</version>
+      </dependency>
       <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
@@ -633,6 +644,11 @@
         <artifactId>jersey-server</artifactId>
         <version>${jersey.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.glassfish.jersey.ext</groupId>
+        <artifactId>jersey-bean-validation</artifactId>
+        <version>${jersey.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.glassfish.jersey.ext</groupId>
         <artifactId>jersey-entity-filtering</artifactId>
@@ -658,16 +674,46 @@
         <artifactId>jersey-media-json-jackson</artifactId>
         <version>${jersey.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.glassfish.jersey.test-framework</groupId>
+        <artifactId>jersey-test-framework-core</artifactId>
+        <version>${jersey.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+        <version>${jersey.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.glassfish.web</groupId>
+        <artifactId>el-impl</artifactId>
+        <version>2.2</version>
+      </dependency>
+      <dependency>
+        <groupId>org.glassfish.web</groupId>
+        <artifactId>javax.el</artifactId>
+        <version>2.2.4</version>
+      </dependency>
       <dependency>
         <groupId>org.hamcrest</groupId>
         <artifactId>hamcrest-core</artifactId>
         <version>1.3</version>
       </dependency>
+      <dependency>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-validator</artifactId>
+        <version>5.1.3.Final</version>
+      </dependency>
       <dependency>
         <groupId>org.javassist</groupId>
         <artifactId>javassist</artifactId>
         <version>3.18.1-GA</version>
       </dependency>
+      <dependency>
+        <groupId>org.jboss.logging</groupId>
+        <artifactId>jboss-logging</artifactId>
+        <version>3.1.3.GA</version>
+      </dependency>
       <dependency>
         <groupId>org.powermock</groupId>
         <artifactId>powermock-api-easymock</artifactId>
@@ -1040,11 +1086,14 @@
                 <unusedDeclaredDependency>org.apache.hadoop:hadoop-minicluster:jar:${hadoop.version}</unusedDeclaredDependency>
                 <unusedDeclaredDependency>org.apache.httpcomponents:httpclient:jar:${httpclient.version}</unusedDeclaredDependency>
                 <unusedDeclaredDependency>org.glassfish.jersey.containers:jersey-container-jetty-http:jar:${jersey.version}</unusedDeclaredDependency>
+                <unusedDeclaredDependency>org.glassfish.jersey.ext:jersey-bean-validation:jar:${jersey.version}</unusedDeclaredDependency>
+                <unusedDeclaredDependency>org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:jar:${jersey.version}</unusedDeclaredDependency>
                 <unusedDeclaredDependency>org.powermock:powermock-api-easymock:jar:${powermock.version}</unusedDeclaredDependency>
                 <unusedDeclaredDependency>org.slf4j:slf4j-log4j12:jar:${slf4j.version}</unusedDeclaredDependency>
                 <unusedDeclaredDependency>org.apache.httpcomponents:httpclient:jar:${httpclient.version}</unusedDeclaredDependency>
                 <unusedDeclaredDependency>junit:junit:jar:4.12</unusedDeclaredDependency>
                 <unusedDeclaredDependency>javax.servlet:javax.servlet-api:jar:${servlet.api.version}</unusedDeclaredDependency>
+                <unusedDeclaredDependency>javax.el:javax.el-api:jar:${javax.el.version}</unusedDeclaredDependency>
               </ignoredUnusedDeclaredDependencies>
             </configuration>
           </execution>
diff --git a/server/monitor/pom.xml b/server/monitor/pom.xml
index 8229d572fc..f22a48ba47 100644
--- a/server/monitor/pom.xml
+++ b/server/monitor/pom.xml
@@ -44,6 +44,10 @@
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>javax.validation</groupId>
+      <artifactId>validation-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>javax.ws.rs</groupId>
       <artifactId>javax.ws.rs-api</artifactId>
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
index 68317b376e..868d32897a 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
@@ -90,6 +90,7 @@
 import org.glassfish.jersey.jackson.JacksonFeature;
 import org.glassfish.jersey.logging.LoggingFeature;
 import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
 import org.glassfish.jersey.server.mvc.MvcFeature;
 import org.glassfish.jersey.server.mvc.freemarker.FreemarkerMvcFeature;
 import org.glassfish.jersey.servlet.ServletContainer;
@@ -547,13 +548,14 @@ public Resource getResource(String pathInContext) {
   private ServletHolder getViewServlet() {
     final ResourceConfig rc = new ResourceConfig().packages("org.apache.accumulo.monitor.view")
         .register(new LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getSimpleName()))).register(FreemarkerMvcFeature.class)
-        .property(MvcFeature.TEMPLATE_BASE_PATH, "/templates");
+        .property(MvcFeature.TEMPLATE_BASE_PATH, "/templates").property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
     return new ServletHolder(new ServletContainer(rc));
   }
 
   private ServletHolder getRestServlet() {
     final ResourceConfig rc = new ResourceConfig().packages("org.apache.accumulo.monitor.rest")
-        .register(new LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getSimpleName()))).register(JacksonFeature.class);
+        .register(new LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getSimpleName()))).register(JacksonFeature.class)
+        .property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
     return new ServletHolder(new ServletContainer(rc));
   }
 
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
index 8c7fed764c..f85f036f64 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/problems/ProblemsResource.java
@@ -16,11 +16,16 @@
  */
 package org.apache.accumulo.monitor.rest.problems;
 
+import static org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
+import static org.apache.accumulo.monitor.util.ParameterValidator.RESOURCE_REGEX;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -36,6 +41,7 @@
 import org.apache.accumulo.server.problems.ProblemReport;
 import org.apache.accumulo.server.problems.ProblemReports;
 import org.apache.accumulo.server.problems.ProblemType;
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -93,12 +99,12 @@ public ProblemSummary getSummary() {
   @POST
   @Consumes(MediaType.TEXT_PLAIN)
   @Path("summary")
-  public void clearTableProblems(@QueryParam("s") String tableID) {
+  public void clearTableProblems(@QueryParam("s") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String tableID) {
     Logger log = LoggerFactory.getLogger(Monitor.class);
     try {
       ProblemReports.getInstance(Monitor.getContext()).deleteProblemReports(Table.ID.of(tableID));
     } catch (Exception e) {
-      log.error("Failed to delete problem reports for table " + tableID, e);
+      log.error("Failed to delete problem reports for table " + (StringUtils.isEmpty(tableID) ? StringUtils.EMPTY : tableID), e);
     }
   }
 
@@ -144,12 +150,13 @@ public ProblemDetail getDetails() {
   @POST
   @Consumes(MediaType.TEXT_PLAIN)
   @Path("details")
-  public void clearDetailsProblems(@QueryParam("table") String tableID, @QueryParam("resource") String resource, @QueryParam("ptype") String ptype) {
+  public void clearDetailsProblems(@QueryParam("table") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String tableID, @QueryParam("resource") @NotNull @Pattern(
+      regexp = RESOURCE_REGEX) String resource, @QueryParam("ptype") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String ptype) {
     Logger log = LoggerFactory.getLogger(Monitor.class);
     try {
       ProblemReports.getInstance(Monitor.getContext()).deleteProblemReport(Table.ID.of(tableID), ProblemType.valueOf(ptype), resource);
     } catch (Exception e) {
-      log.error("Failed to delete problem reports for table " + tableID, e);
+      log.error("Failed to delete problem reports for table " + (StringUtils.isBlank(tableID) ? "" : tableID), e);
     }
   }
 
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
index 8031931fb1..41d3825305 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tables/TablesResource.java
@@ -16,6 +16,11 @@
  */
 package org.apache.accumulo.monitor.rest.tables;
 
+import static org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
+import static org.apache.accumulo.monitor.util.ParameterValidator.NAMESPACE_LIST_REGEX;
+import static org.apache.accumulo.monitor.util.ParameterValidator.NAMESPACE_REGEX;
+
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -26,6 +31,8 @@
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -51,6 +58,7 @@
 import org.apache.accumulo.server.master.state.TabletLocationState;
 import org.apache.accumulo.server.tables.TableManager;
 import org.apache.accumulo.server.util.TableInfoUtil;
+import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.io.Text;
 
 /**
@@ -65,6 +73,7 @@
 public class TablesResource {
 
   private static final TabletServerStatus NO_STATUS = new TabletServerStatus();
+  private static final java.util.regex.Pattern COMMA = java.util.regex.Pattern.compile(",");
 
   /**
    * Generates a table list based on the namespace
@@ -81,9 +90,11 @@ private static TablesList generateTables(String namespace) {
     /*
      * Add the tables that have the selected namespace Asterisk = All namespaces Hyphen = Default namespace
      */
-    for (String key : namespaces.keySet()) {
-      if (namespace.equals("*") || namespace.equals(key) || (key.isEmpty() && namespace.equals("-"))) {
-        tableNamespace.addTable(new TableNamespace(key));
+    if (null != namespace) {
+      for (String key : namespaces.keySet()) {
+        if (namespace.equals("*") || namespace.equals(key) || (key.isEmpty() && namespace.equals("-"))) {
+          tableNamespace.addTable(new TableNamespace(key));
+        }
       }
     }
 
@@ -161,7 +172,7 @@ public static TablesList getTables() {
    */
   @GET
   @Path("namespace/{namespace}")
-  public TablesList getTable(@PathParam("namespace") String namespace) {
+  public TablesList getTable(@PathParam("namespace") @NotNull @Pattern(regexp = NAMESPACE_REGEX) String namespace) throws UnsupportedEncodingException {
     return generateTables(namespace);
   }
 
@@ -174,14 +185,15 @@ public TablesList getTable(@PathParam("namespace") String namespace) {
    */
   @GET
   @Path("namespaces/{namespaces}")
-  public TablesList getTableWithNamespace(@PathParam("namespaces") String namespaceList) {
+  public TablesList getTableWithNamespace(@PathParam("namespaces") @NotNull @Pattern(regexp = NAMESPACE_LIST_REGEX) String namespaceList)
+      throws UnsupportedEncodingException {
     SortedMap<String,Namespace.ID> namespaces = Namespaces.getNameToIdMap(Monitor.getContext().getInstance());
 
     TablesList tableNamespace = new TablesList();
     /*
      * Add the tables that have the selected namespace Asterisk = All namespaces Hyphen = Default namespace
      */
-    for (String namespace : namespaceList.split(",")) {
+    for (String namespace : COMMA.split(namespaceList)) {
       for (String key : namespaces.keySet()) {
         if (namespace.equals("*") || namespace.equals(key) || (key.isEmpty() && namespace.equals("-"))) {
           tableNamespace.addTable(new TableNamespace(key));
@@ -201,12 +213,16 @@ public TablesList getTableWithNamespace(@PathParam("namespaces") String namespac
    */
   @Path("{tableId}")
   @GET
-  public TabletServers getParticipatingTabletServers(@PathParam("tableId") String tableIdStr) throws Exception {
+  public TabletServers getParticipatingTabletServers(@PathParam("tableId") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String tableIdStr) throws Exception {
     Instance instance = Monitor.getContext().getInstance();
     Table.ID tableId = Table.ID.of(tableIdStr);
 
     TabletServers tabletServers = new TabletServers(Monitor.getMmi().tServerInfo.size());
 
+    if (StringUtils.isBlank(tableIdStr)) {
+      return tabletServers;
+    }
+
     TreeSet<String> locs = new TreeSet<>();
     if (RootTable.ID.equals(tableId)) {
       locs.add(instance.getRootTabletLocation());
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
index 0084427bda..a73623d75a 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/trace/TracesResource.java
@@ -18,6 +18,7 @@
 
 import static java.lang.Math.min;
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
 
 import java.io.IOException;
 import java.security.PrivilegedAction;
@@ -28,6 +29,10 @@
 import java.util.Set;
 import java.util.TreeMap;
 
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -59,6 +64,7 @@
 import org.apache.accumulo.tracer.TraceFormatter;
 import org.apache.accumulo.tracer.thrift.Annotation;
 import org.apache.accumulo.tracer.thrift.RemoteSpan;
+import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.security.UserGroupInformation;
 
@@ -77,12 +83,12 @@
    * Generates a trace summary
    *
    * @param minutes
-   *          Range of minutes to filter traces
+   *          Range of minutes to filter traces Min of 0 minutes, Max of 30 days
    * @return Trace summary in specified range
    */
   @Path("summary/{minutes}")
   @GET
-  public RecentTracesList getTraces(@DefaultValue("10") @PathParam("minutes") int minutes) throws Exception {
+  public RecentTracesList getTraces(@DefaultValue("10") @PathParam("minutes") @NotNull @Min(0) @Max(2592000) int minutes) throws Exception {
 
     RecentTracesList recentTraces = new RecentTracesList();
 
@@ -122,12 +128,13 @@ public Void run() {
    * @param type
    *          Type of the trace
    * @param minutes
-   *          Range of minutes
+   *          Range of minutes, Min of 0 and Max 0f 30 days
    * @return List of traces filtered by type and range
    */
   @Path("listType/{type}/{minutes}")
   @GET
-  public TraceType getTracesType(@PathParam("type") String type, @PathParam("minutes") int minutes) throws Exception {
+  public TraceType getTracesType(@PathParam("type") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) final String type,
+      @PathParam("minutes") @Min(0) @Max(2592000) int minutes) throws Exception {
 
     TraceType typeTraces = new TraceType(type);
 
@@ -175,12 +182,9 @@ public Void run() {
    */
   @Path("show/{id}")
   @GET
-  public TraceList getTracesType(@PathParam("id") String id) throws Exception {
-    TraceList traces = new TraceList(id);
+  public TraceList getTracesType(@PathParam("id") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String id) throws Exception {
 
-    if (id == null) {
-      return null;
-    }
+    TraceList traces = new TraceList(id);
 
     Pair<Scanner,UserGroupInformation> entry = getScanner();
     final Scanner scanner = entry.getFirst();
@@ -258,8 +262,8 @@ protected Range getRangeForTrace(long minutesSince) {
     long startTime = endTime - millisSince;
 
     String startHexTime = Long.toHexString(startTime), endHexTime = Long.toHexString(endTime);
-    while (startHexTime.length() < endHexTime.length()) {
-      startHexTime = "0" + startHexTime;
+    if (startHexTime.length() < endHexTime.length()) {
+      StringUtils.leftPad(startHexTime, endHexTime.length(), '0');
     }
 
     return new Range(new Text("start:" + startHexTime), new Text("start:" + endHexTime));
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
index d96e40dbe3..d966cff68a 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerResource.java
@@ -16,12 +16,16 @@
  */
 package org.apache.accumulo.monitor.rest.tservers;
 
+import static org.apache.accumulo.monitor.util.ParameterValidator.SERVER_REGEX;
+
 import java.lang.management.ManagementFactory;
 import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.List;
 
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -101,7 +105,7 @@ public TabletServers getTserverSummary() {
    */
   @POST
   @Consumes(MediaType.TEXT_PLAIN)
-  public void clearDeadServer(@QueryParam("server") String server) throws Exception {
+  public void clearDeadServer(@QueryParam("server") @NotNull @Pattern(regexp = SERVER_REGEX) String server) throws Exception {
     DeadServerList obit = new DeadServerList(ZooUtil.getRoot(Monitor.getContext().getInstance()) + Constants.ZDEADTSERVERS);
     obit.delete(server);
   }
@@ -140,28 +144,23 @@ public TabletServersRecovery getTserverRecovery() {
   /**
    * Generates details for the selected tserver
    *
-   * @param tserverAddr
+   * @param tserverAddress
    *          TServer name
    * @return TServer details
    */
   @Path("{address}")
   @GET
-  public TabletServerSummary getTserverDetails(@PathParam("address") String tserverAddr) throws Exception {
-
-    String tserverAddress = tserverAddr;
+  public TabletServerSummary getTserverDetails(@PathParam("address") @NotNull @Pattern(regexp = SERVER_REGEX) String tserverAddress) throws Exception {
 
     boolean tserverExists = false;
-    if (tserverAddress != null && tserverAddress.isEmpty() == false) {
-      for (TabletServerStatus ts : Monitor.getMmi().getTServerInfo()) {
-        if (tserverAddress.equals(ts.getName())) {
-          tserverExists = true;
-          break;
-        }
+    for (TabletServerStatus ts : Monitor.getMmi().getTServerInfo()) {
+      if (tserverAddress.equals(ts.getName())) {
+        tserverExists = true;
+        break;
       }
     }
 
-    if (tserverAddress == null || tserverAddress.isEmpty() || tserverExists == false) {
-
+    if (!tserverExists) {
       return null;
     }
 
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/util/ParameterValidator.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/util/ParameterValidator.java
new file mode 100644
index 0000000000..a736a293bd
--- /dev/null
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/util/ParameterValidator.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.monitor.util;
+
+/**
+ * Simple utility class to validate Accumulo Monitor Query and Path parameters
+ */
+public interface ParameterValidator {
+
+  String ALPHA_NUM_REGEX = "\\w+";
+  String ALPHA_NUM_REGEX_BLANK_OK = "\\w*";
+
+  String RESOURCE_REGEX = "(\\w|:)+";
+
+  String NAMESPACE_REGEX = "[*-]?|(\\w)+";
+  String NAMESPACE_LIST_REGEX = "[*-]?|(\\w+,?\\w*)+";
+
+  String SERVER_REGEX = "(\\w+([.-])*\\w*)+(:[0-9]+)*";
+  String SERVER_REGEX_BLANK_OK = "((\\w+([.-])*\\w*)+(:[0-9]+)*)*";
+}
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
index 750ea8cdc1..9e26a484ad 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/view/WebViews.java
@@ -16,14 +16,24 @@
  */
 package org.apache.accumulo.monitor.view;
 
+import static org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX;
+import static org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX_BLANK_OK;
+import static org.apache.accumulo.monitor.util.ParameterValidator.SERVER_REGEX_BLANK_OK;
+import static org.apache.commons.lang.StringUtils.isBlank;
 import static org.apache.commons.lang.StringUtils.isEmpty;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -145,11 +155,11 @@ private void addExternalResources(Map<String,Object> model) {
   @GET
   @Path("tservers")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getTabletServers(@QueryParam("s") String server) {
+  public Map<String,Object> getTabletServers(@QueryParam("s") @Pattern(regexp = SERVER_REGEX_BLANK_OK) String server) {
 
     Map<String,Object> model = getModel();
     model.put("title", "Tablet Server Status");
-    if (server != null) {
+    if (isNotBlank(server)) {
       model.put("template", "server.ftl");
       model.put("js", "server.js");
       model.put("server", server);
@@ -230,17 +240,22 @@ private void addExternalResources(Map<String,Object> model) {
   @GET
   @Path("vis")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getServerActivity(@QueryParam("shape") @DefaultValue("circles") String shape, @QueryParam("size") @DefaultValue("40") String size,
-      @QueryParam("motion") @DefaultValue("") String motion, @QueryParam("color") @DefaultValue("allavg") String color) {
+  public Map<String,Object> getServerActivity(@QueryParam("shape") @DefaultValue("circles") @Pattern(regexp = ALPHA_NUM_REGEX_BLANK_OK) String shape,
+      @QueryParam("size") @DefaultValue("40") @Min(1) @Max(100) int size,
+      @QueryParam("motion") @DefaultValue("") @Pattern(regexp = ALPHA_NUM_REGEX_BLANK_OK) String motion, @QueryParam("color") @DefaultValue("allavg") @Pattern(
+          regexp = ALPHA_NUM_REGEX_BLANK_OK) String color) {
+
+    shape = isNotBlank(shape) ? shape : "circles";
+    color = isNotBlank(color) ? color : "allavg";
 
     Map<String,Object> model = getModel();
     model.put("title", "Server Activity");
     model.put("template", "vis.ftl");
 
     model.put("shape", shape);
-    model.put("size", size);
-    model.put("motion", motion);
-    model.put("color", color);
+    model.put("size", String.valueOf(size));
+    model.put("motion", isBlank(motion) ? "" : motion.trim());
+    model.put("color", isBlank(color) ? "allavg" : color); // Are there a set of acceptable values?
 
     return model;
   }
@@ -274,7 +289,8 @@ private void addExternalResources(Map<String,Object> model) {
   @GET
   @Path("tables/{tableID}")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getTables(@PathParam("tableID") String tableID) throws TableNotFoundException {
+  public Map<String,Object> getTables(@PathParam("tableID") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String tableID) throws TableNotFoundException,
+      UnsupportedEncodingException {
 
     String tableName = Tables.getTableName(Monitor.getContext().getInstance(), Table.ID.of(tableID));
 
@@ -293,20 +309,19 @@ private void addExternalResources(Map<String,Object> model) {
    * Returns trace summary template
    *
    * @param minutes
-   *          Range of minutes
+   *          Range of minutes, default 10 minutes Min of 0 Max of 30 days in minutes
    * @return Trace summary model
    */
   @GET
   @Path("trace/summary")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getTracesSummary(@QueryParam("minutes") @DefaultValue("10") String minutes) {
-
+  public Map<String,Object> getTracesSummary(@QueryParam("minutes") @DefaultValue("10") @Min(0) @Max(2592000) int minutes) {
     Map<String,Object> model = getModel();
-    model.put("title", "Traces for the last&nbsp;" + minutes + "&nbsp;minute(s)");
+    model.put("title", "Traces for the last&nbsp;" + String.valueOf(minutes) + "&nbsp;minute(s)");
 
     model.put("template", "summary.ftl");
     model.put("js", "summary.js");
-    model.put("minutes", minutes);
+    model.put("minutes", String.valueOf(minutes));
 
     return model;
   }
@@ -317,21 +332,21 @@ private void addExternalResources(Map<String,Object> model) {
    * @param type
    *          Type of trace
    * @param minutes
-   *          Range of minutes
+   *          Range of minutes, default 10 minutes Min of 0 Max of 30 days in minutes
    * @return Traces by type model
    */
   @GET
   @Path("trace/listType")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getTracesForType(@QueryParam("type") String type, @QueryParam("minutes") @DefaultValue("10") String minutes) {
-
+  public Map<String,Object> getTracesForType(@QueryParam("type") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String type,
+      @QueryParam("minutes") @DefaultValue("10") @Min(0) @Max(2592000) int minutes) {
     Map<String,Object> model = getModel();
-    model.put("title", "Traces for " + type + " for the last " + minutes + " minute(s)");
+    model.put("title", "Traces for " + type + " for the last " + String.valueOf(minutes) + " minute(s)");
 
     model.put("template", "listType.ftl");
     model.put("js", "listType.js");
     model.put("type", type);
-    model.put("minutes", minutes);
+    model.put("minutes", String.valueOf(minutes));
 
     return model;
   }
@@ -346,7 +361,7 @@ private void addExternalResources(Map<String,Object> model) {
   @GET
   @Path("trace/show")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getTraceShow(@QueryParam("id") String id) {
+  public Map<String,Object> getTraceShow(@QueryParam("id") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX) String id) throws Exception {
 
     Map<String,Object> model = getModel();
     model.put("title", "Trace ID " + id);
@@ -387,7 +402,7 @@ private void addExternalResources(Map<String,Object> model) {
   @GET
   @Path("problems")
   @Template(name = "/default.ftl")
-  public Map<String,Object> getProblems(@QueryParam("table") String table) {
+  public Map<String,Object> getProblems(@QueryParam("table") @Pattern(regexp = ALPHA_NUM_REGEX_BLANK_OK) String table) {
 
     Map<String,Object> model = getModel();
     model.put("title", "Per-Table Problem Report");
@@ -395,7 +410,7 @@ private void addExternalResources(Map<String,Object> model) {
     model.put("template", "problems.ftl");
     model.put("js", "problems.js");
 
-    if (table != null) {
+    if (isNotBlank(table)) {
       model.put("table", table);
     }
 
diff --git a/server/monitor/src/test/java/org/apache/accumulo/monitor/util/ParameterValidatorTest.java b/server/monitor/src/test/java/org/apache/accumulo/monitor/util/ParameterValidatorTest.java
new file mode 100644
index 0000000000..d698029650
--- /dev/null
+++ b/server/monitor/src/test/java/org/apache/accumulo/monitor/util/ParameterValidatorTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.monitor.util;
+
+import java.util.regex.Pattern;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Basic tests for ParameterValidator
+ */
+public class ParameterValidatorTest {
+
+  @Test
+  public void testAlphaNumRegex() {
+    Pattern p = Pattern.compile(ParameterValidator.ALPHA_NUM_REGEX);
+    Assert.assertTrue(p.matcher("asdlkfj234kj324").matches());
+    Assert.assertFalse(p.matcher("234-324").matches());
+    Assert.assertFalse(p.matcher("").matches());
+
+    p = Pattern.compile(ParameterValidator.ALPHA_NUM_REGEX_BLANK_OK);
+    Assert.assertTrue(p.matcher("asdlkfj234kj324").matches());
+    Assert.assertTrue(p.matcher("").matches());
+    Assert.assertFalse(p.matcher("234-324").matches());
+  }
+
+  @Test
+  public void testServerRegex() throws Exception {
+    Pattern p = Pattern.compile(ParameterValidator.SERVER_REGEX);
+    Assert.assertTrue("Did not match hostname with dots", p.matcher("ab3cd.12d34.3xyz.net").matches());
+    Assert.assertTrue("Did not match hostname with dash", p.matcher("abcd.123.server-foo.com").matches());
+    Assert.assertTrue("Did not match hostname and port", p.matcher("abcd.123.server-foo.com:1234").matches());
+    Assert.assertTrue("Did not match all numeric", p.matcher("127.0.0.1").matches());
+    Assert.assertTrue("Did not match all numeric and port", p.matcher("127.0.0.1:9999").matches());
+    Assert.assertTrue("Did not match all numeric and port", p.matcher("ServerName:9999").matches());
+
+    Assert.assertFalse(p.matcher("abcd.1234.*.xyz").matches());
+    Assert.assertFalse(p.matcher("abcd.1234.;xyz").matches());
+    Assert.assertFalse(p.matcher("abcd.12{3}4.xyz").matches());
+    Assert.assertFalse(p.matcher("abcd.12[3]4.xyz").matches());
+    Assert.assertFalse(p.matcher("abcd=4.xyz").matches());
+    Assert.assertFalse(p.matcher("abcd=\"4.xyz\"").matches());
+    Assert.assertFalse(p.matcher("abcd\"4.xyz\"").matches());
+
+    Pattern q = Pattern.compile(ParameterValidator.SERVER_REGEX_BLANK_OK);
+    Assert.assertTrue(q.matcher("abcd:9997").matches());
+    Assert.assertTrue(q.matcher("abcd.123:9997").matches());
+    Assert.assertTrue(q.matcher("abcd.123-xyz:9997").matches());
+    Assert.assertTrue(q.matcher("abcd.123-xyz").matches());
+    Assert.assertTrue(q.matcher("").matches());
+  }
+
+}
diff --git a/test/pom.xml b/test/pom.xml
index 81133b78e5..00ff2c7c1a 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -66,6 +66,14 @@
       <groupId>commons-lang</groupId>
       <artifactId>commons-lang</artifactId>
     </dependency>
+    <dependency>
+      <groupId>javax.el</groupId>
+      <artifactId>javax.el-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.ws.rs</groupId>
+      <artifactId>javax.ws.rs-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>jline</groupId>
       <artifactId>jline</artifactId>
@@ -133,6 +141,17 @@
     <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-client</artifactId>
+      <exclusions>
+        <!-- Pulls in an older jersey version -->
+        <exclusion>
+          <groupId>com.sun.jersey</groupId>
+          <artifactId>jersey-core</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jersey</groupId>
+          <artifactId>jersey-client</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.hadoop</groupId>
@@ -141,6 +160,29 @@
     <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-minicluster</artifactId>
+      <exclusions>
+        <!-- Pulls in an older jersey version -->
+        <exclusion>
+          <groupId>com.sun.jersey</groupId>
+          <artifactId>jersey-client</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jersey</groupId>
+          <artifactId>jersey-core</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jersey</groupId>
+          <artifactId>jersey-json</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jersey</groupId>
+          <artifactId>jersey-server</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jersey.contribs</groupId>
+          <artifactId>jersey-guice</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.hadoop</groupId>
@@ -173,10 +215,34 @@
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.glassfish.jersey.core</groupId>
+      <artifactId>jersey-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.glassfish.jersey.ext</groupId>
+      <artifactId>jersey-bean-validation</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.glassfish.jersey.test-framework</groupId>
+      <artifactId>jersey-test-framework-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+      <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.hamcrest</groupId>
       <artifactId>hamcrest-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-easymock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
diff --git a/test/src/main/java/org/apache/accumulo/test/monitor/WebViewsIT.java b/test/src/main/java/org/apache/accumulo/test/monitor/WebViewsIT.java
new file mode 100644
index 0000000000..8e9169d477
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/monitor/WebViewsIT.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.test.monitor;
+
+import static org.easymock.EasyMock.expect;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.impl.Table;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.conf.DefaultConfiguration;
+import org.apache.accumulo.monitor.Monitor;
+import org.apache.accumulo.monitor.view.WebViews;
+import org.apache.accumulo.server.AccumuloServerContext;
+import org.apache.accumulo.test.categories.SunnyDayTests;
+import org.easymock.EasyMock;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+/**
+ * Basic tests for parameter validation constraints
+ */
+@Category(SunnyDayTests.class)
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Monitor.class, Tables.class})
+public class WebViewsIT extends JerseyTest {
+
+  @Override
+  public Application configure() {
+    enable(TestProperties.LOG_TRAFFIC);
+    enable(TestProperties.DUMP_ENTITY);
+    ResourceConfig config = new ResourceConfig(WebViews.class);
+    config.register(WebViewsIT.HashMapWriter.class);
+    return config;
+  }
+
+  @Override
+  protected void configureClient(ClientConfig config) {
+    super.configureClient(config);
+    config.register(WebViewsIT.HashMapWriter.class);
+  }
+
+  /**
+   * Expect to fail the constraint validation on the REST endpoint. The constraint is the pre-defined word character class Pattern so passing a table name with
+   * punctuation will cause a 400 response code.
+   */
+  @Test
+  public void testGetTablesConstraintViolations() {
+    Response output = target("tables/f+o*o").request().get();
+    Assert.assertEquals("should return status 400", 400, output.getStatus());
+  }
+
+  /**
+   * Test path tables/{tableID} which passes constraints. On passing constraints underlying logic will be executed so we need to mock a certain amount of it.
+   * Note: If you get test failures here due to 500 server response, it's likely an underlying class or method call was added/modified and needs mocking. Note:
+   * To get the proper response code back, you need to make sure jersey has a registered MessageBodyWriter capable of serializing/writing the object returned
+   * from your endpoint. We're using a simple stubbed out inner class HashMapWriter for this.
+   *
+   * @throws Exception
+   *           not expected
+   */
+  @Test
+  public void testGetTablesConstraintPassing() throws Exception {
+    Instance instanceMock = EasyMock.createMock(Instance.class);
+    expect(instanceMock.getInstanceID()).andReturn("foo").anyTimes();
+    AccumuloServerContext contextMock = EasyMock.createMock(AccumuloServerContext.class);
+    expect(contextMock.getInstance()).andReturn(instanceMock).anyTimes();
+    expect(contextMock.getConfiguration()).andReturn(DefaultConfiguration.getInstance()).anyTimes();
+
+    PowerMock.mockStatic(Monitor.class);
+    expect(Monitor.getContext()).andReturn(contextMock).anyTimes();
+
+    PowerMock.mockStatic(Tables.class);
+    expect(Tables.getTableName(instanceMock, Table.ID.of("foo"))).andReturn("bar");
+    PowerMock.replayAll();
+    org.easymock.EasyMock.replay(instanceMock, contextMock);
+
+    // Using the mocks we can verify that the getModel method gets called via debugger
+    // however it's difficult to continue to mock through the jersey MVC code for the properly built response.
+    // Our silly HashMapWriter registered in the configure method gets wired in and used here.
+    Response output = target("tables/foo").request().get();
+    Assert.assertEquals("should return status 200", 200, output.getStatus());
+    String responseBody = output.readEntity(String.class);
+    Assert.assertTrue(responseBody.contains("tableID=foo") && responseBody.contains("table=bar"));
+  }
+
+  /**
+   * Test minutes parameter constraints. When outside range we should get a 400 response.
+   */
+  @Test
+  public void testGetTracesSummaryValidationConstraint() {
+    // Test upper bounds of constraint
+    Response output = target("trace/summary").queryParam("minutes", 5000000).request().get();
+    Assert.assertEquals("should return status 400", 400, output.getStatus());
+
+    // Test lower bounds of constraint
+    output = target("trace/summary").queryParam("minutes", -27).request().get();
+    Assert.assertEquals("should return status 400", 400, output.getStatus());
+  }
+
+  /**
+   * Silly stub to handle MessageBodyWriter for Hashmap. Registered in configure method and auto-wired by Jersey.
+   */
+  public static class HashMapWriter implements MessageBodyWriter<HashMap<?,?>> {
+    @Override
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+      return true;
+    }
+
+    @Override
+    public long getSize(HashMap<?,?> hashMap, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+      return 0;
+    }
+
+    @Override
+    public void writeTo(HashMap<?,?> hashMap, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
+        MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
+      String s = hashMap.toString();
+      entityStream.write(s.getBytes());
+    }
+  }
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message