diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2016-08-31 18:07:29 +0200 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2016-09-01 16:01:12 +0200 |
commit | 3373145c7c35f67eca4d7cec04b49ae02c6587fb (patch) | |
tree | 7e1dccd2c2907742b415bad3bb851241656efe39 /sonar-ws | |
parent | a9dcddb21deaa014255d8bff601515bbdbdf20ff (diff) | |
download | sonarqube-3373145c7c35f67eca4d7cec04b49ae02c6587fb.tar.gz sonarqube-3373145c7c35f67eca4d7cec04b49ae02c6587fb.zip |
SONAR-8004 WS settings/set with a proper WS client
Diffstat (limited to 'sonar-ws')
10 files changed, 183 insertions, 17 deletions
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java index 584d9505ae7..57846b6f2c2 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java @@ -19,13 +19,22 @@ */ package org.sonarqube.ws.client; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.ListMultimap; +import java.util.Collection; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonarqube.ws.MediaTypes; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { @@ -34,8 +43,7 @@ abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { private String mediaType = MediaTypes.JSON; - // keep the same order -> do not use HashMap - private final Map<String, String> params = new LinkedHashMap<>(); + private final DefaultParameters parameters = new DefaultParameters(); BaseRequest(String path) { this.path = path; @@ -60,16 +68,79 @@ abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest { return (SELF) this; } + /** + * To set a multi value parameters, provide a Collection with the values + */ public SELF setParam(String key, @Nullable Object value) { checkArgument(!isNullOrEmpty(key), "a WS parameter key cannot be null"); - if (value != null) { - this.params.put(key, value.toString()); + if (value == null) { + return (SELF) this; + } + + if (value instanceof Collection) { + Collection<Object> values = (Collection<Object>) value; + if (values.isEmpty()) { + return (SELF) this; + } + parameters.setValues(key, values.stream().map(Object::toString).collect(Collectors.toList())); + } else { + parameters.setValue(key, value.toString()); } return (SELF) this; } @Override public Map<String, String> getParams() { - return params; + return parameters.keyValues.keySet().stream() + .collect(Collectors.toMap( + Function.identity(), + key -> parameters.keyValues.get(key).get(0), + (v1, v2) -> { + throw new IllegalStateException(String.format("Duplicate key '%s' in request", v1)); + }, + LinkedHashMap::new)); + } + + @Override + public Parameters getParameters() { + return parameters; + } + + private static class DefaultParameters implements Parameters { + // preserve insertion order + private final ListMultimap<String, String> keyValues = LinkedListMultimap.create(); + + @Override + @CheckForNull + public String getValue(String key) { + return keyValues.containsKey(key) ? keyValues.get(key).get(0) : null; + } + + @Override + public List<String> getValues(String key) { + return keyValues.get(key); + } + + @Override + public Set<String> getKeys() { + return keyValues.keySet(); + } + + private DefaultParameters setValue(String key, String value) { + checkArgument(!isNullOrEmpty(key)); + checkArgument(!isNullOrEmpty(value)); + + keyValues.putAll(key, singletonList(value)); + return this; + } + + private DefaultParameters setValues(String key, Collection<String> values) { + checkArgument(!isNullOrEmpty(key)); + checkArgument(values != null && !values.isEmpty()); + + this.keyValues.putAll(key, values.stream().map(Object::toString).collect(Collectors.toList())); + + return this; + } } } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java index 0ffe844c408..1231c6c7069 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java @@ -162,9 +162,10 @@ public class HttpConnector implements WsConnector { HttpUrl.Builder urlBuilder = baseUrl .resolve(path.startsWith("/") ? path.replaceAll("^(/)+", "") : path) .newBuilder(); - for (Map.Entry<String, String> param : wsRequest.getParams().entrySet()) { - urlBuilder.addQueryParameter(param.getKey(), param.getValue()); - } + wsRequest.getParameters().getKeys() + .forEach(key -> wsRequest.getParameters().getValues(key) + .forEach(value -> urlBuilder.addQueryParameter(key, value))); + return urlBuilder; } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java index ca8947e64e7..52e6392f847 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/LocalWsConnector.java @@ -24,6 +24,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.util.List; import org.sonar.api.server.ws.LocalConnector; import static java.nio.charset.StandardCharsets.UTF_8; @@ -55,9 +56,11 @@ class LocalWsConnector implements WsConnector { private static class DefaultLocalRequest implements LocalConnector.LocalRequest { private final WsRequest wsRequest; + private final Parameters parameters; public DefaultLocalRequest(WsRequest wsRequest) { this.wsRequest = wsRequest; + this.parameters = wsRequest.getParameters(); } @Override @@ -77,12 +80,17 @@ class LocalWsConnector implements WsConnector { @Override public boolean hasParam(String key) { - return wsRequest.getParams().containsKey(key); + return !parameters.getValues(key).isEmpty(); } @Override public String getParam(String key) { - return wsRequest.getParams().get(key); + return parameters.getValue(key); + } + + @Override + public List<String> getMultiParam(String key) { + return parameters.getValues(key); } } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/Parameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/Parameters.java new file mode 100644 index 00000000000..f2ad75bf960 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/Parameters.java @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program 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.sonarqube.ws.client; + +import java.util.List; +import java.util.Set; +import javax.annotation.CheckForNull; + +public interface Parameters { + /** + * In the case of a multi value parameter, returns the first element + */ + @CheckForNull + String getValue(String key); + + List<String> getValues(String key); + + Set<String> getKeys(); +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java index 91db5b8a18e..2c52bc50840 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsRequest.java @@ -32,8 +32,17 @@ public interface WsRequest { String getMediaType(); + /** + * + * In case of multi value parameters, returns the first value + * + * @deprecated since 6.1. Use {@link #getParameters()} instead + */ + @Deprecated Map<String, String> getParams(); + Parameters getParameters(); + enum Method { GET, POST } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SetRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SetRequest.java index 2c09dbd107a..d427fd0d9e1 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SetRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SetRequest.java @@ -21,7 +21,6 @@ package org.sonarqube.ws.client.setting; import java.util.List; -import java.util.Map; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -32,7 +31,7 @@ public class SetRequest { private final String key; private final String value; private final List<String> values; - private final List<Map<String, String>> fieldValues; + private final List<String> fieldValues; private final String componentId; private final String componentKey; @@ -58,7 +57,7 @@ public class SetRequest { return values; } - public List<Map<String, String>> getFieldValues() { + public List<String> getFieldValues() { return fieldValues; } @@ -80,7 +79,7 @@ public class SetRequest { private String key; private String value; private List<String> values = emptyList(); - private List<Map<String, String>> fieldValues = emptyList(); + private List<String> fieldValues = emptyList(); private String componentId; private String componentKey; @@ -103,7 +102,7 @@ public class SetRequest { return this; } - public Builder setFieldValues(List<Map<String, String>> fieldValues) { + public Builder setFieldValues(List<String> fieldValues) { this.fieldValues = fieldValues; return this; } diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsService.java index f55de07baca..388bed8616d 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsService.java @@ -33,9 +33,11 @@ import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_RESET; import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_SET; import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_VALUES; import static org.sonarqube.ws.client.setting.SettingsWsParameters.CONTROLLER_SETTINGS; +import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_FIELD_VALUES; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEY; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_VALUE; +import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_VALUES; public class SettingsService extends BaseService { public SettingsService(WsConnector wsConnector) { @@ -61,6 +63,8 @@ public class SettingsService extends BaseService { call(new PostRequest(path(ACTION_SET)) .setParam(PARAM_KEY, request.getKey()) .setParam(PARAM_VALUE, request.getValue()) + .setParam(PARAM_VALUES, request.getValues()) + .setParam(PARAM_FIELD_VALUES, request.getFieldValues()) .setParam(PARAM_COMPONENT_ID, request.getComponentId()) .setParam(PARAM_COMPONENT_KEY, request.getComponentKey())); } diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java index 50c74985e92..1abb05f2db3 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java @@ -19,11 +19,16 @@ */ package org.sonarqube.ws.client; +import com.google.common.collect.ImmutableList; +import java.util.Arrays; +import java.util.List; +import org.assertj.core.data.MapEntry; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonarqube.ws.MediaTypes; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; @@ -51,12 +56,24 @@ public class BaseRequestTest { @Test public void keep_order_of_params() { assertThat(underTest.getParams()).isEmpty(); + assertThat(underTest.getParameters().getKeys()).isEmpty(); underTest.setParam("keyB", "b"); assertThat(underTest.getParams()).containsExactly(entry("keyB", "b")); + assertParameters(entry("keyB", "b")); + assertMultiValueParameters(entry("keyB", singletonList("b"))); underTest.setParam("keyA", "a"); assertThat(underTest.getParams()).containsExactly(entry("keyB", "b"), entry("keyA", "a")); + assertParameters(entry("keyB", "b"), entry("keyA", "a")); + assertMultiValueParameters(entry("keyB", singletonList("b")), entry("keyA", singletonList("a"))); + + underTest.setParam("keyC", ImmutableList.of("c1", "c2", "c3")); + assertParameters(entry("keyB", "b"), entry("keyA", "a"), entry("keyC", "c1")); + assertMultiValueParameters( + entry("keyB", singletonList("b")), + entry("keyA", singletonList("a")), + entry("keyC", ImmutableList.of("c1", "c2", "c3"))); } @Test @@ -71,6 +88,20 @@ public class BaseRequestTest { underTest.setParam(null, "val"); } + private void assertParameters(MapEntry<String, String>... values) { + Parameters parameters = underTest.getParameters(); + assertThat(parameters.getKeys()).extracting(key -> MapEntry.entry(key, parameters.getValue(key))).containsExactly(values); + } + + private void assertMultiValueParameters(MapEntry<String, List<String>>... expectedParameters) { + Parameters parameters = underTest.getParameters(); + String[] expectedKeys = Arrays.stream(expectedParameters).map(MapEntry::getKey).toArray(String[]::new); + assertThat(parameters.getKeys()).containsExactly(expectedKeys); + Arrays.stream(expectedParameters).forEach(expectedParameter -> { + assertThat(parameters.getValues(expectedParameter.getKey())).containsExactly(expectedParameter.getValue().toArray(new String[0])); + }); + } + private static class FakeRequest extends BaseRequest<FakeRequest> { FakeRequest(String path) { super(path); diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/ServiceTester.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/ServiceTester.java index 89758a70d9d..06f41cd38ac 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/ServiceTester.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/ServiceTester.java @@ -325,7 +325,7 @@ public class ServiceTester<T extends BaseService> extends ExternalResource { isNotNull(); MapEntry<String, String> entry = MapEntry.entry(key, values.toString()); - Assertions.assertThat(actual.getParams()).contains(entry); + Assertions.assertThat(actual.getParameters().getValues(key)).containsExactly(values.toArray(new String[0])); this.assertedParams.add(entry); return this; diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/setting/SettingsServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/setting/SettingsServiceTest.java index 9fe11418c09..82cfba4d457 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/setting/SettingsServiceTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/setting/SettingsServiceTest.java @@ -28,13 +28,16 @@ import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.ServiceTester; import org.sonarqube.ws.client.WsConnector; +import static com.google.common.collect.Lists.newArrayList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT_ID; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT_KEY; +import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_FIELD_VALUES; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEY; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS; import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_VALUE; +import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_VALUES; public class SettingsServiceTest { @@ -76,7 +79,8 @@ public class SettingsServiceTest { underTest.set(SetRequest.builder() .setKey("sonar.debt") .setValue("8h") - // TODO WS Client must handle multi value param + .setValues(newArrayList("v1", "v2", "v3")) + .setFieldValues(newArrayList("json1","json2","json3")) .setComponentId("UUID") .setComponentKey("KEY") .build()); @@ -84,6 +88,8 @@ public class SettingsServiceTest { serviceTester.assertThat(serviceTester.getPostRequest()) .hasParam(PARAM_KEY, "sonar.debt") .hasParam(PARAM_VALUE, "8h") + .hasParam(PARAM_VALUES, newArrayList("v1", "v2", "v3")) + .hasParam(PARAM_FIELD_VALUES, newArrayList("json1", "json2", "json3")) .hasParam(PARAM_COMPONENT_ID, "UUID") .hasParam(PARAM_COMPONENT_KEY, "KEY") .andNoOtherParam(); |