From: Jean-Baptiste Lievremont Date: Mon, 28 Apr 2014 15:56:43 +0000 (+0200) Subject: SONAR-5111 Add support for default parameters in Java WS, protection against undeclar... X-Git-Tag: 4.4-RC1~1369 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=dd38eb3d057eb1eb37a1be1567960906c85f10be;p=sonarqube.git SONAR-5111 Add support for default parameters in Java WS, protection against undeclared params --- diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java index 0dbcfd0aa5c..e4aa651dba7 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java @@ -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; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/server/ws/WebServiceTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/server/ws/WebServiceTest.java index 5848ee53066..c089bfbf2e0 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/server/ws/WebServiceTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/server/ws/WebServiceTest.java @@ -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 index 00000000000..16a83331244 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/ws/InternalRequestWrapper.java @@ -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); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java b/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java index 2faf1cf4127..27349e9e578 100644 --- a/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java +++ b/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java @@ -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 messages = Lists.newArrayList(); String exceptionMessage = message(e.getMessage(), e.l10nKey(), e.l10nParams()); diff --git a/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java b/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java index 3a7aa81ede7..03baa5579a0 100644 --- a/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java +++ b/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java @@ -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); }