diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2019-08-08 11:22:13 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-08-14 20:21:12 +0200 |
commit | 980b9f16b8a34364489d2ed3a8472f725eea4770 (patch) | |
tree | cf6e56931905baa05ae17de93d803ccbdd4c75f0 /server/sonar-server/src | |
parent | 28147b8b05a5244c93e13b51924acfc683bd93f6 (diff) | |
download | sonarqube-980b9f16b8a34364489d2ed3a8472f725eea4770.tar.gz sonarqube-980b9f16b8a34364489d2ed3a8472f725eea4770.zip |
create sonar-webserver-es from sonar-server
ie. move WS engine to dedicated project
Diffstat (limited to 'server/sonar-server/src')
46 files changed, 48 insertions, 3625 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java deleted file mode 100644 index 7a2fdf7166d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.exceptions; - -import com.google.common.base.MoreObjects; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; -import static java.util.Arrays.asList; - -/** - * Request is not valid and can not be processed. - */ -public class BadRequestException extends ServerException { - - private final transient List<String> errors; - - private BadRequestException(List<String> errors) { - super(HTTP_BAD_REQUEST, errors.get(0)); - this.errors = errors; - } - - public static BadRequestException create(List<String> errorMessages) { - checkArgument(!errorMessages.isEmpty(), "At least one error message is required"); - checkArgument(errorMessages.stream().noneMatch(message -> message == null || message.isEmpty()), "Message cannot be empty"); - return new BadRequestException(errorMessages); - } - - public static BadRequestException create(String... errorMessages) { - return create(asList(errorMessages)); - } - - public List<String> errors() { - return errors; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("errors", errors) - .toString(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/ForbiddenException.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/ForbiddenException.java deleted file mode 100644 index d72eefbd02f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/ForbiddenException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.exceptions; - -import com.google.common.base.Preconditions; - -import static java.net.HttpURLConnection.HTTP_FORBIDDEN; - -/** - * Permission denied. User does not have the required permissions. - */ -public class ForbiddenException extends ServerException { - - public ForbiddenException(String message) { - super(HTTP_FORBIDDEN, Preconditions.checkNotNull(message)); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/Message.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/Message.java deleted file mode 100644 index c069ead73d2..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/Message.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.exceptions; - -import com.google.common.base.Preconditions; - -import static com.google.common.base.Strings.isNullOrEmpty; -import static java.lang.String.format; - -public class Message { - - private final String msg; - - private Message(String format, Object... params) { - Preconditions.checkArgument(!isNullOrEmpty(format), "Message cannot be empty"); - this.msg = format(format, params); - } - - public String getMessage() { - return msg; - } - - public static Message of(String msg, Object... arguments) { - return new Message(msg, arguments); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Message other = (Message) o; - return this.msg.equals(other.msg); - } - - @Override - public int hashCode() { - return msg.hashCode(); - } - - @Override - public String toString() { - return msg; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/NotFoundException.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/NotFoundException.java deleted file mode 100644 index ff5fb2f13c4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/NotFoundException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.exceptions; - -import static java.net.HttpURLConnection.HTTP_NOT_FOUND; - -public class NotFoundException extends ServerException { - - public NotFoundException(String message) { - super(HTTP_NOT_FOUND, message); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java deleted file mode 100644 index 491c17ed437..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.exceptions; - -import static java.util.Objects.requireNonNull; - -public class ServerException extends RuntimeException { - private final int httpCode; - - public ServerException(int httpCode, String message) { - super(requireNonNull(message, "Error message cannot be null")); - this.httpCode = httpCode; - } - - public int httpCode() { - return httpCode; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/UnauthorizedException.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/UnauthorizedException.java deleted file mode 100644 index 0b4af12beee..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/UnauthorizedException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.exceptions; - -import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; - -/** - * User needs to be authenticated. HTTP request is generally redirected to login form. - */ -public class UnauthorizedException extends ServerException { - - public UnauthorizedException(String message) { - super(HTTP_UNAUTHORIZED, message); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/exceptions/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/exceptions/package-info.java deleted file mode 100644 index c1ac144f25a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/exceptions/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.server.exceptions; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueWsModule.java index 2fb05802fa9..30b70b5f08a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueWsModule.java @@ -31,7 +31,6 @@ import org.sonar.server.issue.workflow.IssueWorkflow; import org.sonar.server.qualitygate.changeevent.QGChangeEventListenersImpl; import org.sonar.server.settings.ProjectConfigurationLoaderImpl; import org.sonar.server.webhook.WebhookQGChangeEventListener; -import org.sonar.server.ws.WsResponseCommonFormat; public class IssueWsModule extends Module { @Override @@ -50,7 +49,6 @@ public class IssueWsModule extends Module { SearchResponseLoader.class, SearchResponseFormat.class, OperationResponseWriter.class, - WsResponseCommonFormat.class, AddCommentAction.class, EditCommentAction.class, DeleteCommentAction.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java index 9a92a1db6fb..2f17f592203 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java @@ -44,7 +44,6 @@ import org.sonar.db.user.UserDto; import org.sonar.markdown.Markdown; import org.sonar.server.es.Facets; import org.sonar.server.issue.workflow.Transition; -import org.sonar.server.ws.WsResponseCommonFormat; import org.sonarqube.ws.Common; import org.sonarqube.ws.Issues; import org.sonarqube.ws.Issues.Actions; @@ -77,13 +76,11 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; public class SearchResponseFormat { private final Durations durations; - private final WsResponseCommonFormat commonFormat; private final Languages languages; private final AvatarResolver avatarFactory; - public SearchResponseFormat(Durations durations, WsResponseCommonFormat commonFormat, Languages languages, AvatarResolver avatarFactory) { + public SearchResponseFormat(Durations durations, Languages languages, AvatarResolver avatarFactory) { this.durations = durations; - this.commonFormat = commonFormat; this.languages = languages; this.avatarFactory = avatarFactory; } @@ -138,7 +135,14 @@ public class SearchResponseFormat { response.setP(paging.pageIndex()); response.setPs(paging.pageSize()); response.setTotal(paging.total()); - response.setPaging(commonFormat.formatPaging(paging)); + response.setPaging(formatPaging(paging)); + } + + private Common.Paging.Builder formatPaging(Paging paging) { + return Common.Paging.newBuilder() + .setPageIndex(paging.pageIndex()) + .setPageSize(paging.pageSize()) + .setTotal(paging.total()); } private List<Issues.Issue> formatIssues(Set<SearchAdditionalField> fields, SearchResponseData data) { @@ -316,11 +320,25 @@ public class SearchResponseFormat { Common.Rules.Builder wsRules = Common.Rules.newBuilder(); List<RuleDefinitionDto> rules = firstNonNull(data.getRules(), emptyList()); for (RuleDefinitionDto rule : rules) { - wsRules.addRules(commonFormat.formatRule(rule)); + wsRules.addRules(formatRule(rule)); } return wsRules; } + private Common.Rule.Builder formatRule(RuleDefinitionDto rule) { + Common.Rule.Builder builder = Common.Rule.newBuilder() + .setKey(rule.getKey().toString()) + .setName(nullToEmpty(rule.getName())) + .setStatus(Common.RuleStatus.valueOf(rule.getStatus().name())); + + builder.setLang(nullToEmpty(rule.getLanguage())); + Language lang = languages.get(rule.getLanguage()); + if (lang != null) { + builder.setLangName(lang.getName()); + } + return builder; + } + private static List<Issues.Component> formatComponents(SearchResponseData data) { Collection<ComponentDto> components = data.getComponents(); List<Issues.Component> result = new ArrayList<>(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java index aec99251571..3083e4e34e1 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/ComponentAction.java @@ -62,6 +62,7 @@ import org.sonar.server.qualityprofile.QPMeasureData; import org.sonar.server.qualityprofile.QualityProfile; import org.sonar.server.ui.PageRepository; import org.sonar.server.user.UserSession; +import org.sonar.server.ws.WsUtils; import static java.lang.String.format; import static java.util.Collections.emptySortedSet; @@ -76,10 +77,10 @@ import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesEx import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; -import static org.sonar.server.ws.WsUtils.checkComponentNotAModuleAndNotADirectory; public class ComponentAction implements NavigationWsAction { + private static final Set<String> MODULE_OR_DIR_QUALIFIERS = ImmutableSet.of(Qualifiers.MODULE, Qualifiers.DIRECTORY); static final String PARAM_COMPONENT = "component"; private static final String PARAM_BRANCH = "branch"; private static final String PARAM_PULL_REQUEST = "pullRequest"; @@ -177,6 +178,10 @@ public class ComponentAction implements NavigationWsAction { } } + private static void checkComponentNotAModuleAndNotADirectory(ComponentDto component) { + WsUtils.checkRequest(!MODULE_OR_DIR_QUALIFIERS.contains(component.qualifier()), "Operation not supported for module or directory components"); + } + private ComponentDto getRootProjectOrBranch(ComponentDto component, DbSession session) { if (!component.isRootProject()) { return dbClient.componentDao().selectOrFailByUuid(session, component.projectUuid()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/CacheWriter.java b/server/sonar-server/src/main/java/org/sonar/server/ws/CacheWriter.java deleted file mode 100644 index 75ffb3a6449..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/CacheWriter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import org.apache.commons.io.IOUtils; - -/** - * Writer that writes only when closing the resource - */ -class CacheWriter extends Writer { - private final StringWriter bufferWriter; - private final Writer outputWriter; - private boolean isClosed; - - CacheWriter(Writer outputWriter) { - this.bufferWriter = new StringWriter(); - this.outputWriter = outputWriter; - this.isClosed = false; - } - - @Override - public void write(char[] cbuf, int off, int len) { - bufferWriter.write(cbuf, off, len); - } - - @Override - public void flush() { - bufferWriter.flush(); - } - - @Override - public void close() throws IOException { - if (isClosed) { - return; - } - - IOUtils.write(bufferWriter.toString(), outputWriter); - outputWriter.close(); - this.isClosed = true; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/DefaultLocalResponse.java b/server/sonar-server/src/main/java/org/sonar/server/ws/DefaultLocalResponse.java deleted file mode 100644 index 07c11840a16..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/DefaultLocalResponse.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.base.Throwables; -import com.google.common.collect.Maps; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Map; -import javax.annotation.CheckForNull; -import org.apache.commons.io.IOUtils; -import org.sonar.api.server.ws.LocalConnector; -import org.sonar.api.server.ws.Response; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.api.utils.text.XmlWriter; -import org.sonarqube.ws.MediaTypes; - -public class DefaultLocalResponse implements Response, LocalConnector.LocalResponse { - - private final InMemoryStream stream = new InMemoryStream(); - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - private final Map<String, String> headers = Maps.newHashMap(); - - @Override - public int getStatus() { - return stream().status(); - } - - @Override - public String getMediaType() { - return stream().mediaType(); - } - - @Override - public byte[] getBytes() { - return output.toByteArray(); - } - - public class InMemoryStream implements Response.Stream { - private String mediaType; - - private int status = 200; - - @CheckForNull - public String mediaType() { - return mediaType; - } - - public int status() { - return status; - } - - @Override - public Response.Stream setMediaType(String s) { - this.mediaType = s; - return this; - } - - @Override - public Response.Stream setStatus(int i) { - this.status = i; - return this; - } - - @Override - public OutputStream output() { - return output; - } - - } - - @Override - public JsonWriter newJsonWriter() { - stream.setMediaType(MediaTypes.JSON); - return JsonWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8)); - } - - @Override - public XmlWriter newXmlWriter() { - stream.setMediaType(MediaTypes.XML); - return XmlWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8)); - } - - @Override - public InMemoryStream stream() { - return stream; - } - - @Override - public Response noContent() { - stream().setStatus(HttpURLConnection.HTTP_NO_CONTENT); - IOUtils.closeQuietly(output); - return this; - } - - public String outputAsString() { - return new String(output.toByteArray(), StandardCharsets.UTF_8); - } - - @Override - public Response setHeader(String name, String value) { - headers.put(name, value); - return this; - } - - @Override - public Collection<String> getHeaderNames() { - return headers.keySet(); - } - - @Override - public String getHeader(String name) { - return headers.get(name); - } - - public byte[] getFlushedOutput() { - try { - output.flush(); - return output.toByteArray(); - } catch (IOException e) { - throw Throwables.propagate(e); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedPropertiesWsFilter.java b/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedPropertiesWsFilter.java index 95a09bc4925..7d67c785764 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedPropertiesWsFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedPropertiesWsFilter.java @@ -37,15 +37,11 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.sonar.api.web.ServletFilter; import org.sonar.server.property.ws.IndexAction; +import org.sonar.server.setting.ws.SettingsWsParameters; import static com.google.common.base.Strings.isNullOrEmpty; import static java.nio.charset.StandardCharsets.UTF_8; import static org.sonar.server.property.ws.PropertiesWs.CONTROLLER_PROPERTIES; -import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_COMPONENT; -import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_KEY; -import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_KEYS; -import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_VALUE; -import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_VALUES; /** * This filter is used to execute deprecated api/properties WS, that were using REST @@ -107,12 +103,12 @@ public class DeprecatedPropertiesWsFilter extends ServletFilter { } @Override - protected String readParam(String key) { + public String readParam(String key) { return restResponse.additionalParams.get(key); } @Override - protected List<String> readMultiParam(String key) { + public List<String> readMultiParam(String key) { return new ArrayList<>(restResponse.additionalMultiParams.get(key)); } @@ -219,20 +215,20 @@ public class DeprecatedPropertiesWsFilter extends ServletFilter { } private void redirectToSet(Optional<String> key, List<String> values, Optional<String> component) { - addParameterIfPresent(PARAM_KEY, key); + addParameterIfPresent(SettingsWsParameters.PARAM_KEY, key); if (values.size() == 1) { - additionalParams.put(PARAM_VALUE, values.get(0)); + additionalParams.put(SettingsWsParameters.PARAM_VALUE, values.get(0)); } else { - additionalMultiParams.putAll(PARAM_VALUES, values); + additionalMultiParams.putAll(SettingsWsParameters.PARAM_VALUES, values); } - addParameterIfPresent(PARAM_COMPONENT, component); + addParameterIfPresent(SettingsWsParameters.PARAM_COMPONENT, component); redirectedPath = "api/settings/set"; redirectedMethod = "POST"; } private void redirectToReset(Optional<String> key, Optional<String> component) { - addParameterIfPresent(PARAM_KEYS, key); - addParameterIfPresent(PARAM_COMPONENT, component); + addParameterIfPresent(SettingsWsParameters.PARAM_KEYS, key); + addParameterIfPresent(SettingsWsParameters.PARAM_COMPONENT, component); redirectedPath = "api/settings/reset"; redirectedMethod = "POST"; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/JsonWriterUtils.java b/server/sonar-server/src/main/java/org/sonar/server/ws/JsonWriterUtils.java deleted file mode 100644 index dec4bbc67c4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/JsonWriterUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.util.Collection; -import java.util.Date; -import javax.annotation.Nullable; -import org.sonar.api.utils.text.JsonWriter; - -public class JsonWriterUtils { - - private JsonWriterUtils() { - // Utility class - } - - public static void writeIfNeeded(JsonWriter json, @Nullable String value, String field, @Nullable Collection<String> fields) { - if (isFieldNeeded(field, fields)) { - json.prop(field, value); - } - } - - public static void writeIfNeeded(JsonWriter json, @Nullable Boolean value, String field, @Nullable Collection<String> fields) { - if (isFieldNeeded(field, fields)) { - json.prop(field, value); - } - } - - public static void writeIfNeeded(JsonWriter json, @Nullable Integer value, String field, @Nullable Collection<String> fields) { - if (isFieldNeeded(field, fields)) { - json.prop(field, value); - } - } - - public static void writeIfNeeded(JsonWriter json, @Nullable Long value, String field, @Nullable Collection<String> fields) { - if (isFieldNeeded(field, fields)) { - json.prop(field, value); - } - } - - public static void writeIfNeeded(JsonWriter json, @Nullable Date value, String field, @Nullable Collection<String> fields) { - if (isFieldNeeded(field, fields)) { - json.propDateTime(field, value); - } - } - - public static boolean isFieldNeeded(String field, @Nullable Collection<String> fields) { - return fields == null || fields.isEmpty() || fields.contains(field); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/KeyExamples.java b/server/sonar-server/src/main/java/org/sonar/server/ws/KeyExamples.java deleted file mode 100644 index ef8773deec0..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/KeyExamples.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -public class KeyExamples { - public static final String KEY_FILE_EXAMPLE_001 = "my_project:/src/foo/Bar.php"; - public static final String KEY_FILE_EXAMPLE_002 = "another_project:/src/foo/Foo.php"; - public static final String KEY_PROJECT_EXAMPLE_001 = "my_project"; - public static final String KEY_PROJECT_EXAMPLE_002 = "another_project"; - public static final String KEY_PROJECT_EXAMPLE_003 = "third_project"; - - public static final String KEY_ORG_EXAMPLE_001 = "my-org"; - public static final String KEY_ORG_EXAMPLE_002 = "foo-company"; - - public static final String KEY_BRANCH_EXAMPLE_001 = "feature/my_branch"; - public static final String KEY_PULL_REQUEST_EXAMPLE_001 = "5461"; - - public static final String NAME_WEBHOOK_EXAMPLE_001 = "My Webhook"; - public static final String URL_WEBHOOK_EXAMPLE_001 = "https://www.my-webhook-listener.com/sonar"; - - private KeyExamples() { - // prevent instantiation - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/LocalRequestAdapter.java b/server/sonar-server/src/main/java/org/sonar/server/ws/LocalRequestAdapter.java deleted file mode 100644 index 849ce475240..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/LocalRequestAdapter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.sonar.api.server.ws.LocalConnector; -import org.sonar.api.impl.ws.ValidatingRequest; - -public class LocalRequestAdapter extends ValidatingRequest { - - private final LocalConnector.LocalRequest localRequest; - - public LocalRequestAdapter(LocalConnector.LocalRequest localRequest) { - this.localRequest = localRequest; - } - - @Override - protected String readParam(String key) { - return localRequest.getParam(key); - } - - @Override - public Map<String, String[]> getParams() { - return localRequest.getParameterMap(); - } - - @Override - protected List<String> readMultiParam(String key) { - return localRequest.getMultiParam(key); - } - - @Override - protected InputStream readInputStreamParam(String key) { - String value = readParam(key); - if (value == null) { - return null; - } - return new ByteArrayInputStream(value.getBytes(StandardCharsets.UTF_8)); - } - - @Override - protected Part readPart(String key) { - throw new UnsupportedOperationException("reading part is not supported yet by local WS calls"); - } - - @Override - public boolean hasParam(String key) { - return localRequest.hasParam(key); - } - - @Override - public String getPath() { - return localRequest.getPath(); - } - - @Override - public String method() { - return localRequest.getMethod(); - } - - @Override - public String getMediaType() { - return localRequest.getMediaType(); - } - - @Override - public Optional<String> header(String name) { - return localRequest.getHeader(name); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/RemovedWebServiceHandler.java b/server/sonar-server/src/main/java/org/sonar/server/ws/RemovedWebServiceHandler.java deleted file mode 100644 index 1b2f608ecd8..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/RemovedWebServiceHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.io.Resources; -import java.net.URL; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.Response; -import org.sonar.server.exceptions.ServerException; - -import static java.net.HttpURLConnection.HTTP_GONE; - -/** - * Used to declare web services that are removed - */ -public enum RemovedWebServiceHandler implements RequestHandler { - - INSTANCE; - - @Override - public void handle(Request request, Response response) { - throw new ServerException(HTTP_GONE, String.format("The web service '%s' doesn't exist anymore, please read its documentation to use alternatives", request.getPath())); - } - - public URL getResponseExample() { - return Resources.getResource(RemovedWebServiceHandler.class, "removed-ws-example.json"); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/RequestVerifier.java b/server/sonar-server/src/main/java/org/sonar/server/ws/RequestVerifier.java deleted file mode 100644 index c5e86345593..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/RequestVerifier.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.WebService; -import org.sonar.server.exceptions.ServerException; - -import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED; - -public class RequestVerifier { - private RequestVerifier() { - // static methods only - } - - public static void verifyRequest(WebService.Action action, Request request) { - switch (request.method()) { - case "GET": - if (action.isPost()) { - throw new ServerException(SC_METHOD_NOT_ALLOWED, "HTTP method POST is required"); - } - return; - case "PUT": - case "DELETE": - throw new ServerException(SC_METHOD_NOT_ALLOWED, String.format("HTTP method %s is not allowed", request.method())); - default: - // Nothing to do - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/ServletFilterHandler.java b/server/sonar-server/src/main/java/org/sonar/server/ws/ServletFilterHandler.java deleted file mode 100644 index 7ae51e2241b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/ServletFilterHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.Response; - -/** - * Used to declare web services that are implemented by a servlet filter. - */ -public class ServletFilterHandler implements RequestHandler { - - public static final RequestHandler INSTANCE = new ServletFilterHandler(); - - private ServletFilterHandler() { - // Nothing - } - - @Override - public void handle(Request request, Response response) { - throw new UnsupportedOperationException("This web service is implemented as a servlet filter"); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/ServletRequest.java b/server/sonar-server/src/main/java/org/sonar/server/ws/ServletRequest.java deleted file mode 100644 index 966e0422315..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/ServletRequest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.net.HttpHeaders; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import javax.annotation.CheckForNull; -import javax.servlet.http.HttpServletRequest; -import org.sonar.api.impl.ws.PartImpl; -import org.sonar.api.impl.ws.ValidatingRequest; -import org.sonar.api.utils.log.Loggers; -import org.sonarqube.ws.MediaTypes; - -import static com.google.common.base.MoreObjects.firstNonNull; -import static java.util.Collections.emptyList; -import static java.util.Locale.ENGLISH; -import static org.apache.commons.lang.StringUtils.substringAfterLast; -import static org.apache.tomcat.util.http.fileupload.FileUploadBase.MULTIPART; - -public class ServletRequest extends ValidatingRequest { - - private final HttpServletRequest source; - - static final Map<String, String> SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX = ImmutableMap.of( - "json", MediaTypes.JSON, - "protobuf", MediaTypes.PROTOBUF, - "text", MediaTypes.TXT); - - public ServletRequest(HttpServletRequest source) { - this.source = source; - } - - @Override - public String method() { - return source.getMethod(); - } - - @Override - public String getMediaType() { - return firstNonNull( - mediaTypeFromUrl(source.getRequestURI()), - firstNonNull( - acceptedContentTypeInResponse(), - MediaTypes.DEFAULT)); - } - - @Override - public BufferedReader getReader() { - try { - return source.getReader(); - } catch (IOException e) { - throw new IllegalStateException("Failed to read", e); - } - } - - @Override - public boolean hasParam(String key) { - return source.getParameterMap().containsKey(key); - } - - @Override - protected String readParam(String key) { - return source.getParameter(key); - } - - @Override - public Map<String, String[]> getParams() { - return source.getParameterMap(); - } - - @Override - protected List<String> readMultiParam(String key) { - String[] values = source.getParameterValues(key); - return values == null ? emptyList() : ImmutableList.copyOf(values); - } - - @Override - protected InputStream readInputStreamParam(String key) { - Part part = readPart(key); - return (part == null) ? null : part.getInputStream(); - } - - @Override - @CheckForNull - public Part readPart(String key) { - try { - if (!isMultipartContent()) { - return null; - } - javax.servlet.http.Part part = source.getPart(key); - if (part == null || part.getSize() == 0) { - return null; - } - return new PartImpl(part.getInputStream(), part.getSubmittedFileName()); - } catch (Exception e) { - Loggers.get(ServletRequest.class).warn("Can't read file part for parameter " + key, e); - return null; - } - } - - private boolean isMultipartContent() { - String contentType = source.getContentType(); - return contentType != null && contentType.toLowerCase(ENGLISH).startsWith(MULTIPART); - } - - @Override - public String toString() { - StringBuffer url = source.getRequestURL(); - String query = source.getQueryString(); - if (query != null) { - url.append("?").append(query); - } - return url.toString(); - } - - @CheckForNull - private String acceptedContentTypeInResponse() { - return source.getHeader(HttpHeaders.ACCEPT); - } - - @CheckForNull - private static String mediaTypeFromUrl(String url) { - String formatSuffix = substringAfterLast(url, "."); - return SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX.get(formatSuffix.toLowerCase(ENGLISH)); - } - - @Override - public String getPath() { - return source.getRequestURI().replaceFirst(source.getContextPath(), ""); - } - - @Override - public Optional<String> header(String name) { - return Optional.ofNullable(source.getHeader(name)); - } - - @Override - public Map<String, String> getHeaders() { - ImmutableMap.Builder<String, String> mapBuilder = ImmutableMap.builder(); - Enumeration<String> headerNames = source.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - mapBuilder.put(headerName, source.getHeader(headerName)); - } - return mapBuilder.build(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/ServletResponse.java b/server/sonar-server/src/main/java/org/sonar/server/ws/ServletResponse.java deleted file mode 100644 index 2f385b89bcd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/ServletResponse.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import javax.servlet.http.HttpServletResponse; -import org.sonar.api.server.ws.Response; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.api.utils.text.XmlWriter; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.sonarqube.ws.MediaTypes.JSON; -import static org.sonarqube.ws.MediaTypes.XML; - -public class ServletResponse implements Response { - - private final ServletStream stream; - - public ServletResponse(HttpServletResponse response) { - stream = new ServletStream(response); - } - - public static class ServletStream implements Stream { - private final HttpServletResponse response; - - public ServletStream(HttpServletResponse response) { - this.response = response; - this.response.setStatus(200); - // SONAR-6964 WS should not be cached by browser - this.response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - } - - @Override - public ServletStream setMediaType(String s) { - this.response.setContentType(s); - return this; - } - - @Override - public ServletStream setStatus(int httpStatus) { - this.response.setStatus(httpStatus); - return this; - } - - @Override - public OutputStream output() { - try { - return response.getOutputStream(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - HttpServletResponse response() { - return response; - } - - public ServletStream reset() { - response.reset(); - return this; - } - } - - @Override - public JsonWriter newJsonWriter() { - stream.setMediaType(JSON); - return JsonWriter.of(new CacheWriter(new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8))); - } - - @Override - public XmlWriter newXmlWriter() { - stream.setMediaType(XML); - return XmlWriter.of(new OutputStreamWriter(stream.output(), UTF_8)); - } - - @Override - public ServletStream stream() { - return stream; - } - - @Override - public Response noContent() { - stream.setStatus(204); - return this; - } - - @Override - public Response setHeader(String name, String value) { - stream.response().setHeader(name, value); - return this; - } - - @Override - public Collection<String> getHeaderNames() { - return stream.response().getHeaderNames(); - } - - @Override - public String getHeader(String name) { - return stream.response().getHeader(name); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java deleted file mode 100644 index e7569e60350..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.base.Throwables; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Locale; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.apache.catalina.connector.ClientAbortException; -import org.picocontainer.Startable; -import org.sonar.api.server.ServerSide; -import org.sonar.api.server.ws.LocalConnector; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.impl.ws.ValidatingRequest; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.ServerException; -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; -import static org.apache.commons.lang.StringUtils.substring; -import static org.apache.commons.lang.StringUtils.substringAfterLast; -import static org.apache.commons.lang.StringUtils.substringBeforeLast; -import static org.sonar.server.ws.RequestVerifier.verifyRequest; -import static org.sonar.server.ws.ServletRequest.SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX; -import static org.sonar.server.ws.WsUtils.checkFound; - -/** - * @since 4.2 - */ -@ServerSide -public class WebServiceEngine implements LocalConnector, Startable { - - private static final Logger LOGGER = Loggers.get(WebServiceEngine.class); - - private final WebService[] webServices; - - private WebService.Context context; - - public WebServiceEngine(WebService[] webServices) { - this.webServices = webServices; - } - - @Override - public void start() { - context = new WebService.Context(); - for (WebService webService : webServices) { - webService.define(context); - } - } - - @Override - public void stop() { - // nothing - } - - private WebService.Context getContext() { - return requireNonNull(context, "Web services has not yet been initialized"); - } - - List<WebService.Controller> controllers() { - return getContext().controllers(); - } - - @Override - public LocalResponse call(LocalRequest request) { - DefaultLocalResponse localResponse = new DefaultLocalResponse(); - execute(new LocalRequestAdapter(request), localResponse); - return localResponse; - } - - public void execute(Request request, Response response) { - try { - ActionExtractor actionExtractor = new ActionExtractor(request.getPath()); - WebService.Action action = getAction(actionExtractor); - checkFound(action, "Unknown url : %s", request.getPath()); - if (request instanceof ValidatingRequest) { - ((ValidatingRequest) request).setAction(action); - ((ValidatingRequest) request).setLocalConnector(this); - } - checkActionExtension(actionExtractor.getExtension()); - verifyRequest(action, request); - action.handler().handle(request, response); - } catch (IllegalArgumentException e) { - sendErrors(request, response, e, 400, singletonList(e.getMessage())); - } catch (BadRequestException e) { - sendErrors(request, response, e, 400, e.errors()); - } catch (ServerException e) { - sendErrors(request, response, e, e.httpCode(), singletonList(e.getMessage())); - } catch (Exception e) { - sendErrors(request, response, e, 500, singletonList("An error has occurred. Please contact your administrator")); - } - } - - @CheckForNull - private WebService.Action getAction(ActionExtractor actionExtractor) { - String controllerPath = actionExtractor.getController(); - String actionKey = actionExtractor.getAction(); - WebService.Controller controller = getContext().controller(controllerPath); - return controller == null ? null : controller.action(actionKey); - } - - private static void sendErrors(Request request, Response response, Exception exception, int status, List<String> errors) { - if (isRequestAbortedByClient(exception)) { - // do not pollute logs. We can't do anything -> use DEBUG level - // see org.sonar.server.ws.ServletResponse#output() - LOGGER.debug(String.format("Request %s has been aborted by client", request), exception); - if (!isResponseCommitted(response)) { - // can be useful for access.log - response.stream().setStatus(299); - } - return; - } - - if (status == 500) { - // Sending exception message into response is a vulnerability. Error must be - // displayed only in logs. - LOGGER.error("Fail to process request " + request, exception); - } - - Response.Stream stream = response.stream(); - if (isResponseCommitted(response)) { - // status can't be changed - LOGGER.debug(String.format("Request %s failed during response streaming", request), exception); - return; - } - - // response is not committed, status and content can be changed to return the error - if (stream instanceof ServletResponse.ServletStream) { - ((ServletResponse.ServletStream) stream).reset(); - } - stream.setStatus(status); - stream.setMediaType(MediaTypes.JSON); - try (JsonWriter json = JsonWriter.of(new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8))) { - json.beginObject(); - writeErrors(json, errors); - json.endObject(); - } catch (Exception e) { - // Do not hide the potential exception raised in the try block. - throw Throwables.propagate(e); - } - } - - private static boolean isRequestAbortedByClient(Exception exception) { - return Throwables.getCausalChain(exception).stream().anyMatch(t -> t instanceof ClientAbortException); - } - - private static boolean isResponseCommitted(Response response) { - Response.Stream stream = response.stream(); - // Request has been aborted by the client or the response was partially streamed, nothing can been done as Tomcat has committed the response - return stream instanceof ServletResponse.ServletStream && ((ServletResponse.ServletStream) stream).response().isCommitted(); - } - - public static void writeErrors(JsonWriter json, List<String> errorMessages) { - if (errorMessages.isEmpty()) { - return; - } - json.name("errors").beginArray(); - errorMessages.forEach(message -> { - json.beginObject(); - json.prop("msg", message); - json.endObject(); - }); - json.endArray(); - } - - private static void checkActionExtension(@Nullable String actionExtension) { - if (isNullOrEmpty(actionExtension)) { - return; - } - checkArgument(SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX.get(actionExtension.toLowerCase(Locale.ENGLISH)) != null, "Unknown action extension: %s", actionExtension); - } - - private static class ActionExtractor { - private static final String SLASH = "/"; - private static final String POINT = "."; - - private final String controller; - private final String action; - private final String extension; - private final String path; - - ActionExtractor(String path) { - this.path = path; - String pathWithoutExtension = substringBeforeLast(path, POINT); - this.controller = extractController(pathWithoutExtension); - this.action = substringAfterLast(pathWithoutExtension, SLASH); - checkArgument(!action.isEmpty(), "Url is incorrect : '%s'", path); - this.extension = substringAfterLast(path, POINT); - } - - private static String extractController(String path) { - String controller = substringBeforeLast(path, SLASH); - if (controller.startsWith(SLASH)) { - return substring(controller, 1); - } - return controller; - } - - String getController() { - return controller; - } - - String getAction() { - return action; - } - - @CheckForNull - String getExtension() { - return extension; - } - - String getPath() { - return path; - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java index b9856283552..ebd1b3aefca 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java @@ -30,9 +30,9 @@ import org.sonar.api.SonarRuntime; import org.sonar.api.server.ws.WebService; import org.sonar.api.web.ServletFilter; import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.server.property.ws.PropertiesWs; import static java.util.stream.Stream.concat; -import static org.sonar.server.property.ws.PropertiesWs.CONTROLLER_PROPERTIES; import static org.sonar.server.ws.WebServiceReroutingFilter.MOVED_WEB_SERVICES; /** @@ -60,7 +60,7 @@ public class WebServiceFilter extends ServletFilter { .map(toPath())) .collect(MoreCollectors.toSet()); this.excludeUrls = concat(concat( - Stream.of("/" + CONTROLLER_PROPERTIES + "*"), + Stream.of("/" + PropertiesWs.CONTROLLER_PROPERTIES + "*"), MOVED_WEB_SERVICES.stream()), webServiceEngine.controllers().stream() .flatMap(controller -> controller.actions().stream()) diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WsAction.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WsAction.java deleted file mode 100644 index bb7ed1932d6..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WsAction.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import org.sonar.api.server.ws.Definable; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.WebService; - -/** - * Since 5.2, this interface is the base for Web Service marker interfaces - * Convention for naming implementations: <i>web_service_class_name</i>Action. ex: ProjectsWsAction, UsersWsAction - */ -public interface WsAction extends RequestHandler, Definable<WebService.NewController> { - // Marker interface -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WsParameterBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WsParameterBuilder.java deleted file mode 100644 index 291d9af0a5b..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WsParameterBuilder.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.util.Locale; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; -import org.sonar.api.resources.ResourceType; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.server.ws.WebService; -import org.sonar.core.i18n.I18n; - -import static java.lang.String.format; - -public class WsParameterBuilder { - private static final String PARAM_QUALIFIER = "qualifier"; - private static final String PARAM_QUALIFIERS = "qualifiers"; - - private WsParameterBuilder() { - // static methods only - } - - public static WebService.NewParam createRootQualifierParameter(WebService.NewAction action, QualifierParameterContext context) { - return action.createParam(PARAM_QUALIFIER) - .setDescription("Project qualifier. Filter the results with the specified qualifier. Possible values are:" + buildRootQualifiersDescription(context)) - .setPossibleValues(getRootQualifiers(context.getResourceTypes())); - } - - public static WebService.NewParam createRootQualifiersParameter(WebService.NewAction action, QualifierParameterContext context) { - return action.createParam(PARAM_QUALIFIERS) - .setDescription("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. " + - "Possible values are:" + buildRootQualifiersDescription(context)) - .setPossibleValues(getRootQualifiers(context.getResourceTypes())); - } - - public static WebService.NewParam createDefaultTemplateQualifierParameter(WebService.NewAction action, QualifierParameterContext context) { - return action.createParam(PARAM_QUALIFIER) - .setDescription("Project qualifier. Filter the results with the specified qualifier. Possible values are:" + buildDefaultTemplateQualifiersDescription(context)) - .setPossibleValues(getDefaultTemplateQualifiers(context.getResourceTypes())); - } - - public static WebService.NewParam createQualifiersParameter(WebService.NewAction action, QualifierParameterContext context) { - return action.createParam(PARAM_QUALIFIERS) - .setDescription( - "Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. Possible values are:" + buildAllQualifiersDescription(context)) - .setPossibleValues(getAllQualifiers(context.getResourceTypes())); - } - - private static Set<String> getRootQualifiers(ResourceTypes resourceTypes) { - return resourceTypes.getRoots().stream() - .map(ResourceType::getQualifier) - .collect(Collectors.toCollection(TreeSet::new)); - } - - private static Set<String> getDefaultTemplateQualifiers(ResourceTypes resourceTypes) { - return resourceTypes.getRoots().stream() - .map(ResourceType::getQualifier) - .collect(Collectors.toCollection(TreeSet::new)); - } - - private static Set<String> getAllQualifiers(ResourceTypes resourceTypes) { - return resourceTypes.getAll().stream() - .map(ResourceType::getQualifier) - .collect(Collectors.toCollection(TreeSet::new)); - } - - private static String buildDefaultTemplateQualifiersDescription(QualifierParameterContext context) { - return buildQualifiersDescription(context, getDefaultTemplateQualifiers(context.getResourceTypes())); - } - - private static String buildRootQualifiersDescription(QualifierParameterContext context) { - return buildQualifiersDescription(context, getRootQualifiers(context.getResourceTypes())); - } - - private static String buildAllQualifiersDescription(QualifierParameterContext context) { - return buildQualifiersDescription(context, getAllQualifiers(context.getResourceTypes())); - } - - private static String buildQualifiersDescription(QualifierParameterContext context, Set<String> qualifiers) { - StringBuilder description = new StringBuilder(); - description.append("<ul>"); - String qualifierPattern = "<li>%s - %s</li>"; - for (String qualifier : qualifiers) { - description.append(format(qualifierPattern, qualifier, qualifierLabel(context, qualifier))); - } - description.append("</ul>"); - - return description.toString(); - } - - private static String qualifierLabel(QualifierParameterContext context, String qualifier) { - String qualifiersPropertyPrefix = "qualifiers."; - return context.getI18n().message(Locale.ENGLISH, qualifiersPropertyPrefix + qualifier, "no description available"); - } - - public static class QualifierParameterContext { - private final I18n i18n; - private final ResourceTypes resourceTypes; - - private QualifierParameterContext(I18n i18n, ResourceTypes resourceTypes) { - this.i18n = i18n; - this.resourceTypes = resourceTypes; - } - - public static QualifierParameterContext newQualifierParameterContext(I18n i18n, ResourceTypes resourceTypes) { - return new QualifierParameterContext(i18n, resourceTypes); - } - - public I18n getI18n() { - return i18n; - } - - public ResourceTypes getResourceTypes() { - return resourceTypes; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java deleted file mode 100644 index 3167e90909c..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import org.sonar.api.resources.Language; -import org.sonar.api.resources.Languages; -import org.sonar.api.utils.Paging; -import org.sonar.db.rule.RuleDefinitionDto; -import org.sonarqube.ws.Common; - -import static com.google.common.base.Strings.nullToEmpty; - -public class WsResponseCommonFormat { - - private final Languages languages; - - public WsResponseCommonFormat(Languages languages) { - this.languages = languages; - } - - public Common.Paging.Builder formatPaging(Paging paging) { - return Common.Paging.newBuilder() - .setPageIndex(paging.pageIndex()) - .setPageSize(paging.pageSize()) - .setTotal(paging.total()); - } - - public Common.Rule.Builder formatRule(RuleDefinitionDto rule) { - Common.Rule.Builder builder = Common.Rule.newBuilder() - .setKey(rule.getKey().toString()) - .setName(nullToEmpty(rule.getName())) - .setStatus(Common.RuleStatus.valueOf(rule.getStatus().name())); - - builder.setLang(nullToEmpty(rule.getLanguage())); - Language lang = languages.get(rule.getLanguage()); - if (lang != null) { - builder.setLangName(lang.getName()); - } - return builder; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WsUtils.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WsUtils.java deleted file mode 100644 index 9c144754ba3..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WsUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableSet; -import com.google.protobuf.Message; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.List; -import java.util.Set; -import javax.annotation.Nullable; -import org.apache.commons.io.IOUtils; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.core.util.ProtobufJsonFormat; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; - -import static java.lang.String.format; -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.sonarqube.ws.MediaTypes.JSON; -import static org.sonarqube.ws.MediaTypes.PROTOBUF; - -public class WsUtils { - - private static final Set<String> MODULE_OR_DIR_QUALIFIERS = ImmutableSet.of(Qualifiers.MODULE, Qualifiers.DIRECTORY); - - private WsUtils() { - // only statics - } - - public static void writeProtobuf(Message msg, Request request, Response response) { - OutputStream output = response.stream().output(); - try { - if (request.getMediaType().equals(PROTOBUF)) { - response.stream().setMediaType(PROTOBUF); - msg.writeTo(output); - } else { - response.stream().setMediaType(JSON); - try (JsonWriter writer = JsonWriter.of(new OutputStreamWriter(output, UTF_8))) { - ProtobufJsonFormat.write(msg, writer); - } - } - } catch (Exception e) { - throw new IllegalStateException("Error while writing protobuf message", e); - } finally { - IOUtils.closeQuietly(output); - } - } - - /** - * @throws BadRequestException - */ - public static void checkRequest(boolean expression, String message, Object... messageArguments) { - if (!expression) { - throw BadRequestException.create(format(message, messageArguments)); - } - } - - public static void checkRequest(boolean expression, List<String> messages) { - if (!expression) { - throw BadRequestException.create(messages); - } - } - - /** - * @throws NotFoundException if the value if null - * @return the value - */ - public static <T> T checkFound(@Nullable T value, String message, Object... messageArguments) { - if (value == null) { - throw new NotFoundException(format(message, messageArguments)); - } - - return value; - } - - /** - * @throws NotFoundException if the value is not present - * @return the value - */ - public static <T> T checkFoundWithOptional(Optional<T> value, String message, Object... messageArguments) { - if (!value.isPresent()) { - throw new NotFoundException(format(message, messageArguments)); - } - - return value.get(); - } - - public static <T> T checkFoundWithOptional(java.util.Optional<T> value, String message, Object... messageArguments) { - if (!value.isPresent()) { - throw new NotFoundException(format(message, messageArguments)); - } - - return value.get(); - } - - public static <T> T checkStateWithOptional(java.util.Optional<T> value, String message, Object... messageArguments) { - if (!value.isPresent()) { - throw new IllegalStateException(format(message, messageArguments)); - } - - return value.get(); - } - - public static void checkComponentNotAModuleAndNotADirectory(ComponentDto component) { - checkRequest(!MODULE_OR_DIR_QUALIFIERS.contains(component.qualifier()), "Operation not supported for module or directory components"); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/ws/package-info.java index 464c533bab7..d4209ca34a5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/package-info.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ws/package-info.java @@ -21,3 +21,4 @@ package org.sonar.server.ws; import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ws/removed-ws-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ws/removed-ws-example.json deleted file mode 100644 index 6764a133ed3..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/ws/removed-ws-example.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "errors": [ - { - "msg": "The web service '/api/...' doesn't exists anymore, please read its documentation to use alternatives" - } - ] -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueWsModuleTest.java index 7a44fea9f37..b9c68da85d3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueWsModuleTest.java @@ -30,7 +30,7 @@ public class IssueWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new IssueWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 31); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 30); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java index 9a4bacc317d..1dd9477158e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java @@ -51,7 +51,6 @@ import org.sonar.server.permission.index.WebAuthorizationTypeSupport; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.view.index.ViewIndexer; import org.sonar.server.ws.WsActionTester; -import org.sonar.server.ws.WsResponseCommonFormat; import org.sonarqube.ws.Issues; import org.sonarqube.ws.Issues.Component; import org.sonarqube.ws.Issues.Issue; @@ -105,7 +104,7 @@ public class SearchActionComponentsTest { private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter); private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow)); private Languages languages = new Languages(); - private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), new WsResponseCommonFormat(languages), languages, new AvatarResolverImpl()); + private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new AvatarResolverImpl()); private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer); private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java index 1d5d65750a9..3a1c6530e73 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java @@ -48,7 +48,6 @@ import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.permission.index.WebAuthorizationTypeSupport; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; -import org.sonar.server.ws.WsResponseCommonFormat; import org.sonarqube.ws.Common; import org.sonarqube.ws.Common.FacetValue; import org.sonarqube.ws.Issues.SearchWsResponse; @@ -87,7 +86,7 @@ public class SearchActionFacetsTest { private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(db.getDbClient(), Clock.systemUTC(), userSession); private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, db.getDbClient(), new TransitionService(userSession, null)); private Languages languages = new Languages(); - private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), new WsResponseCommonFormat(languages), languages, new AvatarResolverImpl()); + private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new AvatarResolverImpl()); private WsActionTester ws = new WsActionTester( new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java index 2c6fc63e0db..f3768030a5e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java @@ -68,7 +68,6 @@ import org.sonar.server.permission.index.WebAuthorizationTypeSupport; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; -import org.sonar.server.ws.WsResponseCommonFormat; import org.sonarqube.ws.Common; import org.sonarqube.ws.Common.Severity; import org.sonarqube.ws.Issues; @@ -99,8 +98,6 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_HIDE_COMMENTS; -import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PAGE_INDEX; -import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PAGE_SIZE; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; public class SearchActionTest { @@ -123,7 +120,7 @@ public class SearchActionTest { private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter); private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow)); private Languages languages = new Languages(); - private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), new WsResponseCommonFormat(languages), languages, new AvatarResolverImpl()); + private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new AvatarResolverImpl()); private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, new MapSettings().asConfig(), System2.INSTANCE, dbClient)); private StartupIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client(), issueIndexer); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java index b029c512d7e..6b1aef9fd63 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java @@ -50,7 +50,6 @@ import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.permission.index.WebAuthorizationTypeSupport; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; -import org.sonar.server.ws.WsResponseCommonFormat; import org.sonar.test.JsonAssert; import static org.assertj.core.api.Assertions.assertThat; @@ -77,7 +76,7 @@ public class SearchActionTestOnSonarCloud { private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter); private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow)); private Languages languages = new Languages(); - private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), new WsResponseCommonFormat(languages), languages, new AvatarResolverImpl()); + private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new AvatarResolverImpl()); private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer); private SearchAction underTest = new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/CacheWriterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/CacheWriterTest.java deleted file mode 100644 index 355d4762432..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/CacheWriterTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -public class CacheWriterTest { - private Writer writer = new StringWriter(); - private CacheWriter underTest = new CacheWriter(writer); - - @Test - public void write_content_when_closing_resource() throws IOException { - underTest.write("content"); - assertThat(writer.toString()).isEmpty(); - - underTest.close(); - - assertThat(writer.toString()).isEqualTo("content"); - } - - @Test - public void close_encapsulated_writer_once() throws IOException { - writer = mock(Writer.class); - underTest = new CacheWriter(writer); - - underTest.close(); - underTest.close(); - - verify(writer, times(1)).close(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedPropertiesWsFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedPropertiesWsFilterTest.java index 848eb6eca16..753f4ae0bc3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedPropertiesWsFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedPropertiesWsFilterTest.java @@ -20,7 +20,6 @@ package org.sonar.server.ws; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.util.Arrays; import javax.servlet.FilterChain; import javax.servlet.ReadListener; @@ -250,7 +249,7 @@ public class DeprecatedPropertiesWsFilterTest { } @Test - public void redirect_delete_api_properties_to_api_settings_reset() throws Exception { + public void redirect_delete_api_properties_to_api_settings_reset() { when(request.getRequestURI()).thenReturn("/api/properties/my.property"); when(request.getParameter("resource")).thenReturn("my_project"); when(request.getMethod()).thenReturn("DELETE"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/DumbResponse.java b/server/sonar-server/src/test/java/org/sonar/server/ws/DumbResponse.java deleted file mode 100644 index f7d2aeedd80..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/DumbResponse.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.base.Throwables; -import com.google.common.collect.Maps; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Map; -import javax.annotation.CheckForNull; -import org.apache.commons.io.IOUtils; -import org.sonar.api.server.ws.Response; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.api.utils.text.XmlWriter; - -public class DumbResponse implements Response { - private InMemoryStream stream; - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - - private Map<String, String> headers = Maps.newHashMap(); - - public class InMemoryStream implements Response.Stream { - private String mediaType; - - private int status = 200; - - @CheckForNull - public String mediaType() { - return mediaType; - } - - public int status() { - return status; - } - - @Override - public Response.Stream setMediaType(String s) { - this.mediaType = s; - return this; - } - - @Override - public Response.Stream setStatus(int i) { - this.status = i; - return this; - } - - @Override - public OutputStream output() { - return output; - } - - public String outputAsString() { - return new String(output.toByteArray(), StandardCharsets.UTF_8); - } - } - - @Override - public JsonWriter newJsonWriter() { - return JsonWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8)); - } - - @Override - public XmlWriter newXmlWriter() { - return XmlWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8)); - } - - @Override - public InMemoryStream stream() { - if (stream == null) { - stream = new InMemoryStream(); - } - return stream; - } - - @Override - public Response noContent() { - stream().setStatus(HttpURLConnection.HTTP_NO_CONTENT); - IOUtils.closeQuietly(output); - return this; - } - - public String outputAsString() { - return new String(output.toByteArray(), StandardCharsets.UTF_8); - } - - @Override - public Response setHeader(String name, String value) { - headers.put(name, value); - return this; - } - - public Collection<String> getHeaderNames() { - return headers.keySet(); - } - - @CheckForNull - public String getHeader(String name){ - return headers.get(name); - } - - public byte[] getFlushedOutput() { - try { - output.flush(); - return output.toByteArray(); - } catch (IOException e) { - throw Throwables.propagate(e); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/RemovedWebServiceHandlerTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/RemovedWebServiceHandlerTest.java deleted file mode 100644 index 262a8325845..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/RemovedWebServiceHandlerTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.server.ws.Request; -import org.sonar.server.exceptions.ServerException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class RemovedWebServiceHandlerTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void throw_server_exception() throws Exception { - Request request = mock(Request.class); - when(request.getPath()).thenReturn("/api/resources/index"); - - try { - RemovedWebServiceHandler.INSTANCE.handle(request, null); - fail(); - } catch (ServerException e) { - assertThat(e.getMessage()).isEqualTo("The web service '/api/resources/index' doesn't exist anymore, please read its documentation to use alternatives"); - assertThat(e.httpCode()).isEqualTo(410); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/ServletRequestTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/ServletRequestTest.java deleted file mode 100644 index 502dfa9dec7..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/ServletRequestTest.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.collect.ImmutableMap; -import com.google.common.net.HttpHeaders; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonarqube.ws.MediaTypes; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ServletRequestTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private HttpServletRequest source = mock(HttpServletRequest.class); - - private ServletRequest underTest = new ServletRequest(source); - - @Test - public void call_method() { - underTest.method(); - - verify(source).getMethod(); - } - - @Test - public void getMediaType() { - when(source.getHeader(HttpHeaders.ACCEPT)).thenReturn(MediaTypes.JSON); - when(source.getRequestURI()).thenReturn("/path/to/resource/search"); - - assertThat(underTest.getMediaType()).isEqualTo(MediaTypes.JSON); - } - - @Test - public void default_media_type_is_octet_stream() { - when(source.getRequestURI()).thenReturn("/path/to/resource/search"); - - assertThat(underTest.getMediaType()).isEqualTo(MediaTypes.DEFAULT); - } - - @Test - public void media_type_taken_in_url_first() { - when(source.getHeader(HttpHeaders.ACCEPT)).thenReturn(MediaTypes.JSON); - when(source.getRequestURI()).thenReturn("/path/to/resource/search.protobuf"); - - assertThat(underTest.getMediaType()).isEqualTo(MediaTypes.PROTOBUF); - } - - @Test - public void has_param_from_source() { - when(source.getParameterMap()).thenReturn(ImmutableMap.of("param", new String[] {"value"})); - ServletRequest request = new ServletRequest(source); - assertThat(request.hasParam("param")).isTrue(); - } - - @Test - public void read_param_from_source() { - when(source.getParameter("param")).thenReturn("value"); - - assertThat(underTest.readParam("param")).isEqualTo("value"); - } - - @Test - public void read_multi_param_from_source_with_values() { - when(source.getParameterValues("param")).thenReturn(new String[]{"firstValue", "secondValue", "thirdValue"}); - - List<String> result = underTest.readMultiParam("param"); - - assertThat(result).containsExactly("firstValue", "secondValue", "thirdValue"); - } - - @Test - public void read_multi_param_from_source_with_one_value() { - when(source.getParameterValues("param")).thenReturn(new String[]{"firstValue"}); - - List<String> result = underTest.readMultiParam("param"); - - assertThat(result).containsExactly("firstValue"); - } - - @Test - public void read_multi_param_from_source_without_value() { - when(source.getParameterValues("param")).thenReturn(null); - - List<String> result = underTest.readMultiParam("param"); - - assertThat(result).isEmpty(); - } - - @Test - public void read_input_stream() throws Exception { - when(source.getContentType()).thenReturn("multipart/form-data"); - InputStream file = mock(InputStream.class); - Part part = mock(Part.class); - when(part.getInputStream()).thenReturn(file); - when(part.getSize()).thenReturn(10L); - when(source.getPart("param1")).thenReturn(part); - - assertThat(underTest.readInputStreamParam("param1")).isEqualTo(file); - assertThat(underTest.readInputStreamParam("param2")).isNull(); - } - - @Test - public void read_no_input_stream_when_part_size_is_zero() throws Exception { - when(source.getContentType()).thenReturn("multipart/form-data"); - InputStream file = mock(InputStream.class); - Part part = mock(Part.class); - when(part.getInputStream()).thenReturn(file); - when(part.getSize()).thenReturn(0L); - when(source.getPart("param1")).thenReturn(part); - - assertThat(underTest.readInputStreamParam("param1")).isNull(); - } - - @Test - public void return_no_input_stream_when_content_type_is_not_multipart() { - when(source.getContentType()).thenReturn("multipart/form-data"); - - assertThat(underTest.readInputStreamParam("param1")).isNull(); - } - - @Test - public void return_no_input_stream_when_content_type_is_null() { - when(source.getContentType()).thenReturn(null); - - assertThat(underTest.readInputStreamParam("param1")).isNull(); - } - - @Test - public void returns_null_when_invalid_part() throws Exception { - when(source.getContentType()).thenReturn("multipart/form-data"); - InputStream file = mock(InputStream.class); - Part part = mock(Part.class); - when(part.getSize()).thenReturn(0L); - when(part.getInputStream()).thenReturn(file); - doThrow(IllegalArgumentException.class).when(source).getPart("param1"); - - assertThat(underTest.readInputStreamParam("param1")).isNull(); - } - - @Test - public void getPath() { - when(source.getRequestURI()).thenReturn("/sonar/path/to/resource/search"); - when(source.getContextPath()).thenReturn("/sonar"); - - assertThat(underTest.getPath()).isEqualTo("/path/to/resource/search"); - } - - @Test - public void to_string() { - when(source.getRequestURL()).thenReturn(new StringBuffer("http:localhost:9000/api/issues")); - assertThat(underTest.toString()).isEqualTo("http:localhost:9000/api/issues"); - - when(source.getQueryString()).thenReturn("components=sonar"); - - assertThat(underTest.toString()).isEqualTo("http:localhost:9000/api/issues?components=sonar"); - } - - @Test - public void header_returns_the_value_of_http_header() { - when(source.getHeader("Accept")).thenReturn("text/plain"); - assertThat(underTest.header("Accept")).hasValue("text/plain"); - } - - @Test - public void header_is_empty_if_absent_from_request() { - when(source.getHeader("Accept")).thenReturn(null); - assertThat(underTest.header("Accept")).isEmpty(); - } - - @Test - public void header_has_empty_value_if_present_in_request_without_value() { - when(source.getHeader("Accept")).thenReturn(""); - assertThat(underTest.header("Accept")).hasValue(""); - } - - @Test - public void getReader() throws IOException { - BufferedReader reader = new BufferedReader(new StringReader("foo")); - when(source.getReader()).thenReturn(reader); - - assertThat(underTest.getReader()).isEqualTo(reader); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/ServletResponseTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/ServletResponseTest.java deleted file mode 100644 index aa4cda9ca7b..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/ServletResponseTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonarqube.ws.MediaTypes.JSON; -import static org.sonarqube.ws.MediaTypes.XML; - -public class ServletResponseTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ServletOutputStream output = mock(ServletOutputStream.class); - private HttpServletResponse response = mock(HttpServletResponse.class); - - private ServletResponse underTest = new ServletResponse(response); - - @Before - public void setUp() throws Exception { - when(response.getOutputStream()).thenReturn(output); - } - - @Test - public void test_default_header() { - verify(response).setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - } - - @Test - public void set_header() { - underTest.setHeader("header", "value"); - - verify(response).setHeader("header", "value"); - } - - @Test - public void get_header() { - underTest.getHeader("header"); - - verify(response).getHeader("header"); - } - - @Test - public void get_header_names() { - underTest.getHeaderNames(); - - verify(response).getHeaderNames(); - } - - @Test - public void test_default_status() { - verify(response).setStatus(200); - } - - @Test - public void set_status() { - underTest.stream().setStatus(404); - - verify(response).setStatus(404); - } - - @Test - public void test_output() { - assertThat(underTest.stream().output()).isEqualTo(output); - } - - - @Test - public void test_reset() { - underTest.stream().reset(); - - verify(response).reset(); - } - - @Test - public void test_newJsonWriter() throws Exception { - underTest.newJsonWriter(); - - verify(response).setContentType(JSON); - verify(response).getOutputStream(); - } - - @Test - public void test_newXmlWriter() throws Exception { - underTest.newXmlWriter(); - - verify(response).setContentType(XML); - verify(response).getOutputStream(); - } - - @Test - public void test_noContent() throws Exception { - underTest.noContent(); - - verify(response).setStatus(204); - verify(response, never()).getOutputStream(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/TestRequest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/TestRequest.java deleted file mode 100644 index aea0e0d69bd..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/TestRequest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.base.Throwables; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Maps; -import com.google.protobuf.GeneratedMessageV3; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.StringReader; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import org.apache.commons.io.IOUtils; -import org.sonar.api.impl.ws.PartImpl; -import org.sonar.api.impl.ws.ValidatingRequest; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; -import static org.sonarqube.ws.MediaTypes.PROTOBUF; - -public class TestRequest extends ValidatingRequest { - - private final ListMultimap<String, String> multiParams = ArrayListMultimap.create(); - private final Map<String, String> params = new HashMap<>(); - private final Map<String, String> headers = new HashMap<>(); - private final Map<String, Part> parts = Maps.newHashMap(); - private String payload = ""; - private boolean payloadConsumed = false; - private String method = "GET"; - private String mimeType = "application/octet-stream"; - private String path; - - @Override - public BufferedReader getReader() { - checkState(!payloadConsumed, "Payload already consumed"); - if (payload == null) { - return super.getReader(); - } - - BufferedReader res = new BufferedReader(new StringReader(payload)); - payloadConsumed = true; - return res; - } - - public TestRequest setPayload(String payload) { - checkState(!payloadConsumed, "Payload already consumed"); - - this.payload = payload; - return this; - } - - @Override - protected String readParam(String key) { - return params.get(key); - } - - @Override - protected List<String> readMultiParam(String key) { - return multiParams.get(key); - } - - @Override - protected InputStream readInputStreamParam(String key) { - String value = readParam(key); - if (value == null) { - return null; - } - return IOUtils.toInputStream(value); - } - - @Override - protected Part readPart(String key) { - return parts.get(key); - } - - public TestRequest setPart(String key, InputStream input, String fileName) { - parts.put(key, new PartImpl(input, fileName)); - return this; - } - - @Override - public String method() { - return method; - } - - @Override - public boolean hasParam(String key) { - return params.containsKey(key) || multiParams.containsKey(key); - } - - @Override - public String getPath() { - return path; - } - - @Override - public Map<String, String[]> getParams() { - ArrayListMultimap<String, String> result = ArrayListMultimap.create(multiParams); - params.forEach(result::put); - return result.asMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toArray(new String[0]))); - } - - public TestRequest setPath(String path) { - this.path = path; - return this; - } - - public TestRequest setMethod(String method) { - checkNotNull(method); - this.method = method; - return this; - } - - @Override - public String getMediaType() { - return mimeType; - } - - public TestRequest setMediaType(String type) { - checkNotNull(type); - this.mimeType = type; - return this; - } - - public TestRequest setParam(String key, String value) { - checkNotNull(key); - checkNotNull(value); - this.params.put(key, value); - return this; - } - - public TestRequest setMultiParam(String key, List<String> values) { - requireNonNull(key); - requireNonNull(values); - - multiParams.putAll(key, values); - - return this; - } - - @Override - public Map<String, String> getHeaders() { - return ImmutableMap.copyOf(headers); - } - - @Override - public Optional<String> header(String name) { - return Optional.ofNullable(headers.get(name)); - } - - public TestRequest setHeader(String name, String value) { - headers.put(requireNonNull(name), requireNonNull(value)); - return this; - } - - public TestResponse execute() { - try { - DumbResponse response = new DumbResponse(); - action().handler().handle(this, response); - return new TestResponse(response); - } catch (Exception e) { - throw Throwables.propagate(e); - } - } - - public <T extends GeneratedMessageV3> T executeProtobuf(Class<T> protobufClass) { - return setMediaType(PROTOBUF).execute().getInputObject(protobufClass); - } - - @Override - public String toString() { - return path; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/TestResponse.java b/server/sonar-server/src/test/java/org/sonar/server/ws/TestResponse.java deleted file mode 100644 index 82057f06af0..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/TestResponse.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.protobuf.GeneratedMessageV3; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import javax.annotation.CheckForNull; -import org.sonar.test.JsonAssert; - -public class TestResponse { - - private final DumbResponse dumbResponse; - - TestResponse(DumbResponse dumbResponse) { - this.dumbResponse = dumbResponse; - } - - public InputStream getInputStream() { - return new ByteArrayInputStream(dumbResponse.getFlushedOutput()); - } - - public <T extends GeneratedMessageV3> T getInputObject(Class<T> protobufClass) { - try (InputStream input = getInputStream()) { - Method parseFromMethod = protobufClass.getMethod("parseFrom", InputStream.class); - @SuppressWarnings("unchecked") - T result = (T) parseFromMethod.invoke(null, input); - return result; - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - - public String getInput() { - return new String(dumbResponse.getFlushedOutput(), StandardCharsets.UTF_8); - } - - public String getMediaType() { - return dumbResponse.stream().mediaType(); - } - - public int getStatus() { - return dumbResponse.stream().status(); - } - - @CheckForNull - public String getHeader(String headerKey) { - return dumbResponse.getHeader(headerKey); - } - - public void assertJson(String expectedJson) { - JsonAssert.assertJson(getInput()).isSimilarTo(expectedJson); - } - - /** - * Compares JSON response with JSON file available in classpath. For example if class - * is org.foo.BarTest and filename is index.json, then file must be located - * at src/test/resources/org/foo/BarTest/index.json. - * - * @param clazz the test class - * @param expectedJsonFilename name of the file containing the expected JSON - */ - public void assertJson(Class clazz, String expectedJsonFilename) { - String path = clazz.getSimpleName() + "/" + expectedJsonFilename; - URL url = clazz.getResource(path); - if (url == null) { - throw new IllegalStateException("Cannot find " + path); - } - JsonAssert.assertJson(getInput()).isSimilarTo(url); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java deleted file mode 100644 index 160fce7540f..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.util.function.Consumer; -import javax.servlet.http.HttpServletResponse; -import org.apache.catalina.connector.ClientAbortException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.server.exceptions.BadRequestException; -import org.sonarqube.ws.MediaTypes; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.commons.lang.StringUtils.substringAfterLast; -import static org.apache.commons.lang.StringUtils.substringBeforeLast; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class WebServiceEngineTest { - - @Rule - public LogTester logTester = new LogTester(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void load_ws_definitions_at_startup() { - WebServiceEngine underTest = new WebServiceEngine(new WebService[] { - newWs("api/foo/index", a -> { - }), - newWs("api/bar/index", a -> { - }) - }); - underTest.start(); - try { - assertThat(underTest.controllers()) - .extracting(WebService.Controller::path) - .containsExactlyInAnyOrder("api/foo", "api/bar"); - } finally { - underTest.stop(); - } - } - - @Test - public void ws_returns_successful_response() { - Request request = new TestRequest().setPath("/api/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void accept_path_that_does_not_start_with_slash() { - Request request = new TestRequest().setPath("api/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void request_path_can_contain_valid_media_type() { - Request request = new TestRequest().setPath("api/ping.json"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void bad_request_if_action_suffix_is_not_supported() { - Request request = new TestRequest().setPath("/api/ping.bat"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown action extension: bat\"}]}"); - } - - @Test - public void test_response_with_no_content() { - Request request = new TestRequest().setPath("api/foo"); - - RequestHandler handler = (req, resp) -> resp.noContent(); - DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler(handler))); - - assertThat(response.stream().outputAsString()).isEmpty(); - assertThat(response.stream().status()).isEqualTo(204); - } - - @Test - public void return_404_if_controller_does_not_exist() { - Request request = new TestRequest().setPath("xxx/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown url : xxx/ping\"}]}"); - assertThat(response.stream().status()).isEqualTo(404); - } - - @Test - public void return_404_if_action_does_not_exist() { - Request request = new TestRequest().setPath("api/xxx"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown url : api/xxx\"}]}"); - assertThat(response.stream().status()).isEqualTo(404); - } - - @Test - public void fail_if_method_GET_is_not_allowed() { - Request request = new TestRequest().setMethod("GET").setPath("api/foo"); - - DumbResponse response = run(request, newWs("api/foo", a -> a.setPost(true))); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method POST is required\"}]}"); - assertThat(response.stream().status()).isEqualTo(405); - } - - @Test - public void POST_is_considered_as_GET_if_POST_is_not_supported() { - Request request = new TestRequest().setMethod("POST").setPath("api/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void method_PUT_is_not_allowed() { - Request request = new TestRequest().setMethod("PUT").setPath("/api/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method PUT is not allowed\"}]}"); - assertThat(response.stream().status()).isEqualTo(405); - } - - @Test - public void method_DELETE_is_not_allowed() { - Request request = new TestRequest().setMethod("DELETE").setPath("api/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method DELETE is not allowed\"}]}"); - assertThat(response.stream().status()).isEqualTo(405); - } - - @Test - public void method_POST_is_required() { - Request request = new TestRequest().setMethod("POST").setPath("api/ping"); - - DumbResponse response = run(request, newPingWs(a -> a.setPost(true))); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void fail_if_reading_an_undefined_parameter() { - Request request = new TestRequest().setPath("api/foo").setParam("unknown", "Unknown"); - - DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> request.param("unknown")))); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"BUG - parameter 'unknown' is undefined for action 'foo'\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - } - - @Test - public void fail_if_request_does_not_have_required_parameter() { - Request request = new TestRequest().setPath("api/foo").setParam("unknown", "Unknown"); - - DumbResponse response = run(request, newWs("api/foo", a -> { - a.createParam("bar").setRequired(true); - a.setHandler((req, resp) -> request.mandatoryParam("bar")); - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"The 'bar' parameter is missing\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - } - - @Test - public void fail_if_request_does_not_have_required_parameter_even_if_handler_does_not_require_it() { - Request request = new TestRequest().setPath("api/foo").setParam("unknown", "Unknown"); - - DumbResponse response = run(request, newWs("api/foo", a -> { - a.createParam("bar").setRequired(true); - // do not use mandatoryParam("bar") - a.setHandler((req, resp) -> request.param("bar")); - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"The 'bar' parameter is missing\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - } - - @Test - public void use_default_value_of_optional_parameter() { - Request request = new TestRequest().setPath("api/print"); - - DumbResponse response = run(request, newWs("api/print", a -> { - a.createParam("message").setDefaultValue("hello"); - a.setHandler((req, resp) -> resp.stream().output().write(req.param("message").getBytes(UTF_8))); - })); - - assertThat(response.stream().outputAsString()).isEqualTo("hello"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void use_request_parameter_on_parameter_with_default_value() { - Request request = new TestRequest().setPath("api/print").setParam("message", "bar"); - - DumbResponse response = run(request, newWs("api/print", a -> { - a.createParam("message").setDefaultValue("default_value"); - a.setHandler((req, resp) -> resp.stream().output().write(req.param("message").getBytes(UTF_8))); - })); - - assertThat(response.stream().outputAsString()).isEqualTo("bar"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void accept_parameter_value_within_defined_possible_values() { - Request request = new TestRequest().setPath("api/foo").setParam("format", "json"); - - DumbResponse response = run(request, newWs("api/foo", a -> { - a.createParam("format").setPossibleValues("json", "xml"); - a.setHandler((req, resp) -> resp.stream().output().write(req.mandatoryParam("format").getBytes(UTF_8))); - })); - - assertThat(response.stream().outputAsString()).isEqualTo("json"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void fail_if_parameter_value_is_not_in_defined_possible_values() { - Request request = new TestRequest().setPath("api/foo").setParam("format", "yml"); - - DumbResponse response = run(request, newWs("api/foo", a -> { - a.createParam("format").setPossibleValues("json", "xml"); - a.setHandler((req, resp) -> resp.stream().output().write(req.mandatoryParam("format").getBytes(UTF_8))); - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Value of parameter 'format' (yml) must be one of: [json, xml]\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - } - - @Test - public void return_500_on_internal_error() { - Request request = new TestRequest().setPath("api/foo"); - - DumbResponse response = run(request, newFailWs()); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"An error has occurred. Please contact your administrator\"}]}"); - assertThat(response.stream().status()).isEqualTo(500); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); - assertThat(logTester.logs(LoggerLevel.ERROR)).filteredOn(l -> l.contains("Fail to process request api/foo")).isNotEmpty(); - } - - @Test - public void return_400_on_BadRequestException_with_single_message() { - Request request = new TestRequest().setPath("api/foo"); - - DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> { - throw BadRequestException.create("Bad request !"); - }))); - - assertThat(response.stream().outputAsString()).isEqualTo( - "{\"errors\":[{\"msg\":\"Bad request !\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - } - - @Test - public void return_400_on_BadRequestException_with_multiple_messages() { - Request request = new TestRequest().setPath("api/foo"); - - DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> { - throw BadRequestException.create("one", "two", "three"); - }))); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[" - + "{\"msg\":\"one\"}," - + "{\"msg\":\"two\"}," - + "{\"msg\":\"three\"}" - + "]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - } - - @Test - public void return_error_message_containing_character_percent() { - Request request = new TestRequest().setPath("api/foo"); - - DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> { - throw new IllegalArgumentException("this should not fail %s"); - }))); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"this should not fail %s\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); - } - - @Test - public void send_response_headers() { - Request request = new TestRequest().setPath("api/foo"); - - DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> resp.setHeader("Content-Disposition", "attachment; filename=foo.zip")))); - - assertThat(response.getHeader("Content-Disposition")).isEqualTo("attachment; filename=foo.zip"); - } - - @Test - public void support_aborted_request_when_response_is_already_committed() { - Request request = new TestRequest().setPath("api/foo"); - Response response = mockServletResponse(true); - - run(request, response, newClientAbortWs()); - - // response is committed (status is already sent), so status can't be changed - verify(response.stream(), never()).setStatus(anyInt()); - - assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Request api/foo has been aborted by client"); - } - - @Test - public void support_aborted_request_when_response_is_not_committed() { - Request request = new TestRequest().setPath("api/foo"); - Response response = mockServletResponse(false); - - run(request, response, newClientAbortWs()); - - verify(response.stream()).setStatus(299); - assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Request api/foo has been aborted by client"); - } - - @Test - public void internal_error_when_response_is_already_committed() { - Request request = new TestRequest().setPath("api/foo"); - Response response = mockServletResponse(true); - - run(request, response, newFailWs()); - - // response is committed (status is already sent), so status can't be changed - verify(response.stream(), never()).setStatus(anyInt()); - assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Fail to process request api/foo"); - } - - @Test - public void internal_error_when_response_is_not_committed() { - Request request = new TestRequest().setPath("api/foo"); - Response response = mockServletResponse(false); - - run(request, response, newFailWs()); - - verify(response.stream()).setStatus(500); - assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Fail to process request api/foo"); - } - - @Test - public void fail_when_start_in_not_called() { - Request request = new TestRequest().setPath("/api/ping"); - DumbResponse response = new DumbResponse(); - WebServiceEngine underTest = new WebServiceEngine(new WebService[] {newPingWs(a -> { - })}); - - underTest.execute(request, response); - - assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Fail to process request /api/ping"); - } - - private static WebService newWs(String path, Consumer<WebService.NewAction> consumer) { - return context -> { - WebService.NewController controller = context.createController(substringBeforeLast(path, "/")); - WebService.NewAction action = createNewDefaultAction(controller, substringAfterLast(path, "/")); - action.setHandler((request, response) -> { - }); - consumer.accept(action); - controller.done(); - }; - } - - private static WebService newPingWs(Consumer<WebService.NewAction> consumer) { - return newWs("api/ping", a -> { - a.setHandler((request, response) -> response.stream().output().write("pong".getBytes(UTF_8))); - consumer.accept(a); - }); - } - - private static WebService newFailWs() { - return newWs("api/foo", a -> a.setHandler((req, resp) -> { - throw new IllegalStateException("BOOM"); - })); - } - - private static DumbResponse run(Request request, WebService... webServices) { - DumbResponse response = new DumbResponse(); - return (DumbResponse) run(request, response, webServices); - } - - private static Response run(Request request, Response response, WebService... webServices) { - WebServiceEngine underTest = new WebServiceEngine(webServices); - underTest.start(); - try { - underTest.execute(request, response); - return response; - } finally { - underTest.stop(); - } - } - - private static Response mockServletResponse(boolean committed) { - Response response = mock(Response.class, Mockito.RETURNS_DEEP_STUBS); - ServletResponse.ServletStream servletStream = mock(ServletResponse.ServletStream.class, Mockito.RETURNS_DEEP_STUBS); - when(response.stream()).thenReturn(servletStream); - HttpServletResponse httpServletResponse = mock(HttpServletResponse.class, Mockito.RETURNS_DEEP_STUBS); - when(httpServletResponse.isCommitted()).thenReturn(committed); - when(servletStream.response()).thenReturn(httpServletResponse); - return response; - } - - private static WebService newClientAbortWs() { - return newWs("api/foo", a -> a.setHandler((req, resp) -> { - throw new ClientAbortException(); - })); - } - - private static WebService.NewAction createNewDefaultAction(WebService.NewController controller, String key) { - return controller - .createAction(key) - .setDescription("Dummy Description") - .setSince("5.3") - .setResponseExample(WebServiceEngineTest.class.getResource("web-service-engine-test.txt")); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/WsActionTester.java b/server/sonar-server/src/test/java/org/sonar/server/ws/WsActionTester.java deleted file mode 100644 index fede932156e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/WsActionTester.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.collect.Iterables; -import org.sonar.api.server.ws.WebService; - -public class WsActionTester { - - public static final String CONTROLLER_KEY = "test"; - private final WebService.Action action; - - public WsActionTester(WsAction wsAction) { - WebService.Context context = new WebService.Context(); - WebService.NewController newController = context.createController(CONTROLLER_KEY); - wsAction.define(newController); - newController.done(); - action = Iterables.get(context.controller(CONTROLLER_KEY).actions(), 0); - } - - public WebService.Action getDef() { - return action; - } - - public TestRequest newRequest() { - TestRequest request = new TestRequest(); - request.setAction(action); - return request; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/WsTester.java b/server/sonar-server/src/test/java/org/sonar/server/ws/WsTester.java deleted file mode 100644 index e69153b5033..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/WsTester.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import com.google.common.collect.Maps; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.apache.commons.io.IOUtils; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.impl.ws.PartImpl; -import org.sonar.api.impl.ws.ValidatingRequest; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.api.utils.text.XmlWriter; -import org.sonar.server.ws.WsTester.TestResponse.TestStream; -import org.sonar.test.JsonAssert; -import org.sonarqube.ws.MediaTypes; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static java.util.Objects.requireNonNull; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.server.ws.RequestVerifier.verifyRequest; - -/** - * @since 4.2 - * @deprecated use {@link WsActionTester} in preference to this class - */ -@Deprecated -public class WsTester { - - public static class TestRequest extends ValidatingRequest { - - private final String method; - private String path; - private String mediaType = MediaTypes.JSON; - - private Map<String, String> params = Maps.newHashMap(); - private Map<String, String> headers = Maps.newHashMap(); - private final Map<String, Part> parts = Maps.newHashMap(); - - private TestRequest(String method) { - this.method = method; - } - - @Override - public String method() { - return method; - } - - @Override - public String getMediaType() { - return mediaType; - } - - public TestRequest setMediaType(String s) { - this.mediaType = s; - return this; - } - - @Override - public boolean hasParam(String key) { - return params.keySet().contains(key); - } - - @Override - public Optional<String> header(String name) { - return Optional.ofNullable(headers.get(name)); - } - - public TestRequest setHeader(String name, String value) { - this.headers.put(requireNonNull(name), requireNonNull(value)); - return this; - } - - @Override - public String getPath() { - return path; - } - - public TestRequest setPath(String path) { - this.path = path; - return this; - } - - public TestRequest setParams(Map<String, String> m) { - this.params = m; - return this; - } - - public TestRequest setParam(String key, @Nullable String value) { - if (value != null) { - params.put(key, value); - } - return this; - } - - @Override - protected String readParam(String key) { - return params.get(key); - } - - @Override - protected List<String> readMultiParam(String key) { - String value = params.get(key); - return value == null ? emptyList() : singletonList(value); - } - - @Override - public Map<String, String[]> getParams() { - return params.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> new String[] {e.getValue()})); - } - - @Override - protected InputStream readInputStreamParam(String key) { - String param = readParam(key); - - return param == null ? null : IOUtils.toInputStream(param); - } - - @Override - protected Part readPart(String key) { - return parts.get(key); - } - - public TestRequest setPart(String key, InputStream input, String fileName) { - parts.put(key, new PartImpl(input, fileName)); - return this; - } - - public Result execute() throws Exception { - TestResponse response = new TestResponse(); - verifyRequest(action(), this); - action().handler().handle(this, response); - return new Result(response); - } - } - - public static class TestResponse implements Response { - - private TestStream stream; - - private Map<String, String> headers = Maps.newHashMap(); - - public class TestStream implements Response.Stream { - private String mediaType; - private int status; - - @CheckForNull - public String mediaType() { - return mediaType; - } - - public int status() { - return status; - } - - @Override - public Response.Stream setMediaType(String s) { - this.mediaType = s; - return this; - } - - @Override - public Response.Stream setStatus(int i) { - this.status = i; - return this; - } - - @Override - public OutputStream output() { - return output; - } - } - - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - - @Override - public JsonWriter newJsonWriter() { - return JsonWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8)); - } - - @Override - public XmlWriter newXmlWriter() { - return XmlWriter.of(new OutputStreamWriter(output, StandardCharsets.UTF_8)); - } - - @Override - public Stream stream() { - if (stream == null) { - stream = new TestStream(); - } - return stream; - } - - @Override - public Response noContent() { - stream().setStatus(HttpURLConnection.HTTP_NO_CONTENT); - IOUtils.closeQuietly(output); - return this; - } - - public String outputAsString() { - return new String(output.toByteArray(), StandardCharsets.UTF_8); - } - - @Override - public Response setHeader(String name, String value) { - headers.put(name, value); - return this; - } - - @Override - public Collection<String> getHeaderNames() { - return headers.keySet(); - } - - @Override - public String getHeader(String name) { - return headers.get(name); - } - } - - public static class Result { - private final TestResponse response; - - private Result(TestResponse response) { - this.response = response; - } - - public Result assertNoContent() { - return assertStatus(HttpURLConnection.HTTP_NO_CONTENT); - } - - public String outputAsString() { - return new String(response.output.toByteArray(), StandardCharsets.UTF_8); - } - - public byte[] output() { - return response.output.toByteArray(); - } - - public Result assertJson(String expectedJson) { - String json = outputAsString(); - JsonAssert.assertJson(json).isSimilarTo(expectedJson); - return this; - } - - /** - * Compares JSON response with JSON file available in classpath. For example if class - * is org.foo.BarTest and filename is index.json, then file must be located - * at src/test/resources/org/foo/BarTest/index.json. - * - * @param clazz the test class - * @param expectedJsonFilename name of the file containing the expected JSON - */ - public Result assertJson(Class clazz, String expectedJsonFilename) { - String path = clazz.getSimpleName() + "/" + expectedJsonFilename; - URL url = clazz.getResource(path); - if (url == null) { - throw new IllegalStateException("Cannot find " + path); - } - String json = outputAsString(); - JsonAssert.assertJson(json).isSimilarTo(url); - return this; - } - - public Result assertNotModified() { - return assertStatus(HttpURLConnection.HTTP_NOT_MODIFIED); - } - - public Result assertStatus(int httpStatus) { - assertThat(((TestStream) response.stream()).status()).isEqualTo(httpStatus); - return this; - } - - public Result assertHeader(String name, String value) { - assertThat(response.getHeader(name)).isEqualTo(value); - return this; - } - } - - private final WebService.Context context = new WebService.Context(); - - public WsTester(WebService... webServices) { - for (WebService webService : webServices) { - webService.define(context); - } - } - - public WebService.Context context() { - return context; - } - - @CheckForNull - public WebService.Controller controller(String key) { - return context.controller(key); - } - - @CheckForNull - public WebService.Action action(String controllerKey, String actionKey) { - WebService.Controller controller = context.controller(controllerKey); - if (controller != null) { - return controller.action(actionKey); - } - return null; - } - - public TestRequest newGetRequest(String controllerKey, String actionKey) { - return newRequest(controllerKey, actionKey, "GET"); - } - - public TestRequest newPostRequest(String controllerKey, String actionKey) { - return newRequest(controllerKey, actionKey, "POST"); - } - - private TestRequest newRequest(String controllerKey, String actionKey, String method) { - TestRequest request = new TestRequest(method); - WebService.Controller controller = context.controller(controllerKey); - if (controller == null) { - throw new IllegalArgumentException( - String.format("Controller '%s' is unknown, did you forget to call NewController.done()?", controllerKey)); - } - WebService.Action action = controller.action(actionKey); - if (action == null) { - throw new IllegalArgumentException( - String.format("Action '%s' not found on controller '%s'.", actionKey, controllerKey)); - } - request.setAction(action); - return request; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java deleted file mode 100644 index 5bbd1a9a891..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/WsUtilsTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info 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.sonar.server.ws; - -import java.io.IOException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.log.LogTester; -import org.sonar.server.exceptions.BadRequestException; -import org.sonarqube.ws.Issues; -import org.sonarqube.ws.MediaTypes; -import org.sonarqube.ws.Permissions; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.test.ExceptionCauseMatcher.hasType; - -public class WsUtilsTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public LogTester logger = new LogTester(); - - @Test - public void write_json_by_default() { - TestRequest request = new TestRequest(); - DumbResponse response = new DumbResponse(); - - Issues.Issue msg = Issues.Issue.newBuilder().setKey("I1").build(); - WsUtils.writeProtobuf(msg, request, response); - - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); - assertThat(response.outputAsString()) - .startsWith("{") - .contains("\"key\":\"I1\"") - .endsWith("}"); - } - - @Test - public void write_protobuf() throws Exception { - TestRequest request = new TestRequest(); - request.setMediaType(MediaTypes.PROTOBUF); - DumbResponse response = new DumbResponse(); - - Issues.Issue msg = Issues.Issue.newBuilder().setKey("I1").build(); - WsUtils.writeProtobuf(msg, request, response); - - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.PROTOBUF); - assertThat(Issues.Issue.parseFrom(response.getFlushedOutput()).getKey()).isEqualTo("I1"); - } - - @Test - public void rethrow_error_as_ISE_when_error_writing_message() { - TestRequest request = new TestRequest(); - request.setMediaType(MediaTypes.PROTOBUF); - - Permissions.Permission message = Permissions.Permission.newBuilder().setName("permission-name").build(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectCause(hasType(NullPointerException.class)); - expectedException.expectMessage("Error while writing protobuf message"); - // provoke NullPointerException - WsUtils.writeProtobuf(message, null, new DumbResponse()); - } - - @Test - public void checkRequest_ok() { - WsUtils.checkRequest(true, "Missing param: %s", "foo"); - // do not fail - } - - @Test - public void checkRequest_ko() { - expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Missing param: foo"); - - WsUtils.checkRequest(false, "Missing param: %s", "foo"); - } - -} |