]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5111 Add support for default parameters in Java WS, protection against undeclar...
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 28 Apr 2014 15:56:43 +0000 (17:56 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 28 Apr 2014 15:57:08 +0000 (17:57 +0200)
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
sonar-plugin-api/src/test/java/org/sonar/api/server/ws/WebServiceTest.java
sonar-server/src/main/java/org/sonar/server/ws/InternalRequestWrapper.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java
sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java

index 0dbcfd0aa5c13bffb1eb4e7a3e02a4fbad53bef1..e4aa651dba7dd25e0ba6b6c0d78f356a5cb65c5c 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.ServerExtension;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
+
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -370,7 +371,7 @@ public interface WebService extends ServerExtension {
   }
 
   class NewParam {
-    private String key, description, exampleValue;
+    private String key, description, exampleValue, defaultValue;
     private boolean required = false;
     private String[] possibleValues = null;
 
@@ -410,6 +411,14 @@ public interface WebService extends ServerExtension {
       return this;
     }
 
+    /**
+     * @since 4.4
+     */
+    public NewParam setDefaultValue(@Nullable String s) {
+      this.defaultValue = s;
+      return this;
+    }
+
     @Override
     public String toString() {
       return key;
@@ -418,7 +427,7 @@ public interface WebService extends ServerExtension {
 
   @Immutable
   class Param {
-    private final String key, description, exampleValue;
+    private final String key, description, exampleValue, defaultValue;
     private final boolean required;
     private final String[] possibleValues;
 
@@ -426,6 +435,7 @@ public interface WebService extends ServerExtension {
       this.key = newParam.key;
       this.description = newParam.description;
       this.exampleValue = newParam.exampleValue;
+      this.defaultValue = newParam.defaultValue;
       this.required = newParam.required;
       this.possibleValues = (newParam.possibleValues == null ? new String[0] : newParam.possibleValues);
     }
@@ -462,6 +472,14 @@ public interface WebService extends ServerExtension {
       return possibleValues;
     }
 
+    /**
+     * @since 4.4
+     */
+    @CheckForNull
+    public String defaultValue() {
+      return defaultValue;
+    }
+
     @Override
     public String toString() {
       return key;
index 5848ee5306699b0c975974ad3090e3a85ab22bf8..c089bfbf2e04342c841915ce3192da36177a04a8 100644 (file)
@@ -248,7 +248,7 @@ public class WebServiceTest {
         NewController newController = context.createController("api/rule");
         NewAction create = newController.createAction("create").setHandler(mock(RequestHandler.class));
         create.createParam("key").setDescription("Key of the new rule");
-        create.createParam("severity");
+        create.createParam("severity").setDefaultValue("MAJOR");
         newController.done();
       }
     }.define(context);
@@ -262,6 +262,7 @@ public class WebServiceTest {
 
     assertThat(action.param("severity").key()).isEqualTo("severity");
     assertThat(action.param("severity").description()).isNull();
+    assertThat(action.param("severity").defaultValue()).isEqualTo("MAJOR");
   }
 
   @Test
diff --git a/sonar-server/src/main/java/org/sonar/server/ws/InternalRequestWrapper.java b/sonar-server/src/main/java/org/sonar/server/ws/InternalRequestWrapper.java
new file mode 100644 (file)
index 0000000..16a8333
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.ws;
+
+
+public abstract class InternalRequestWrapper extends InternalRequest {
+
+  private InternalRequest wrapped;
+
+  protected InternalRequestWrapper(InternalRequest request) {
+    this.wrapped = request;
+  }
+
+  @Override
+  public String method() {
+    return wrapped.method();
+  }
+
+  @Override
+  public String param(String key) {
+    return wrapped.param(key);
+  }
+}
index 2faf1cf41270e7d3f5dc64b1052e10cd9cb36ea1..27349e9e5780847a80bb2d8180c5d12aaddb098a 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.ws;
 
+import org.apache.commons.lang.StringUtils;
 import org.elasticsearch.common.collect.Lists;
 import org.picocontainer.Startable;
 import org.slf4j.LoggerFactory;
@@ -26,6 +27,7 @@ import org.sonar.api.ServerComponent;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.BadRequestException.Message;
@@ -82,7 +84,8 @@ public class WebServiceEngine implements ServerComponent, Startable {
       WebService.Action action = getAction(controllerPath, actionKey);
       request.setAction(action);
       verifyRequest(action, request);
-      action.handler().handle(request, response);
+      InternalRequest wrapped = wrapWithDefaults(action, request);
+      action.handler().handle(wrapped, response);
 
     } catch (IllegalArgumentException e) {
       // TODO replace by BadRequestException in Request#mandatoryParam()
@@ -117,6 +120,20 @@ public class WebServiceEngine implements ServerComponent, Startable {
     }
   }
 
+  private InternalRequest wrapWithDefaults(final WebService.Action action, InternalRequest request) {
+    return new InternalRequestWrapper(request) {
+      @Override
+      public String param(String key) {
+        Param paramDef = action.param(key);
+        if (paramDef == null) {
+          throw new BadRequestException(String.format("Parameter '%s' is undefined for action '%s'", key, action.key()));
+        }
+
+        return StringUtils.defaultString(super.param(key), paramDef.defaultValue());
+      }
+    };
+  }
+
   private void sendError(BadRequestException e, ServletResponse response) {
     Collection<String> messages = Lists.newArrayList();
     String exceptionMessage = message(e.getMessage(), e.l10nKey(), e.l10nParams());
index 3a7aa81ede792f931a65dc91053092d43e82eee6..03baa5579a07e7ddbca9083230da649b04b6114e 100644 (file)
@@ -157,6 +157,15 @@ public class WebServiceEngineTest {
     assertThat(response.stream().outputAsString()).isEqualTo("pong");
   }
 
+  @Test
+  public void unknown_parameter_is_set() throws Exception {
+    InternalRequest request = new SimpleRequest().setParam("unknown", "Unknown");
+    ServletResponse response = new ServletResponse();
+    engine.execute(request, response, "api/system", "fail_with_undeclared_parameter");
+
+    assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Parameter 'unknown' is undefined for action 'fail_with_undeclared_parameter'\"}]}");
+  }
+
   @Test
   public void required_parameter_is_not_set() throws Exception {
     InternalRequest request = new SimpleRequest();
@@ -302,6 +311,7 @@ public class WebServiceEngineTest {
           }
         });
       newController.createAction("fail_with_multiple_messages")
+        .createParam("count", "Number of error messages to generate")
         .setHandler(new RequestHandler() {
           @Override
           public void handle(Request request, Response response) {
@@ -313,6 +323,7 @@ public class WebServiceEngineTest {
           }
         });
       newController.createAction("fail_with_multiple_i18n_messages")
+        .createParam("count", "Number of error messages to generate")
         .setHandler(new RequestHandler() {
           @Override
           public void handle(Request request, Response response) {
@@ -338,16 +349,24 @@ public class WebServiceEngineTest {
           }
         });
 
+      newController.createAction("fail_with_undeclared_parameter")
+      .setHandler(new RequestHandler() {
+        @Override
+        public void handle(Request request, Response response) {
+          response.newJsonWriter().prop("unknown", request.param("unknown"));
+        }
+      });
+
       // parameter "message" is required but not "author"
-      newController.createAction("print")
-        .createParam("message", "required message")
-        .createParam("author", "optional author")
-        .setHandler(new RequestHandler() {
+      NewAction print = newController.createAction("print");
+      print.createParam("message").setDescription("required message").setRequired(true);
+      print.createParam("author").setDescription("optional author").setDefaultValue("-");
+      print.setHandler(new RequestHandler() {
           @Override
           public void handle(Request request, Response response) {
             try {
               IOUtils.write(
-                request.mandatoryParam("message") + " by " + request.param("author", "-"), response.stream().output());
+                request.mandatoryParam("message") + " by " + request.param("author", "nobody"), response.stream().output());
             } catch (IOException e) {
               throw new IllegalStateException(e);
             }