quality_profiles.are_you_sure_want_x_profile_as_default=Are you sure that you want to set the profile "{0}" as default?
quality_profiles.profile_x_created=Profile "{0}" created. Set it as default or link it to a project to use it for next measures.
quality_profiles.already_exists=This profile already exists.
+quality_profiles.profile_x_already_exists=Profile "{0}" already exists.
quality_profiles.please_type_profile_name=Please type a profile name.
quality_profiles.profile_x_deleted=Profile "{0}" is deleted.
quality_profiles.default_profile_is_x=Default profile is "{0}".
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.Collections;
-
-import static com.google.common.collect.Lists.newArrayList;
+import java.util.Arrays;
public class ServerException extends RuntimeException {
private final int httpCode;
private final String l10nKey;
- private final Collection<Object> l10nParams;
+ private final Object[] l10nParams;
public ServerException(int httpCode) {
this.httpCode = httpCode;
super(message);
this.httpCode = httpCode;
this.l10nKey = l10nKey;
- this.l10nParams = l10nParams == null ? Collections.emptyList() : Collections.unmodifiableCollection(newArrayList(l10nParams));
+ this.l10nParams = l10nParams;
}
public int httpCode() {
}
@CheckForNull
- public Collection<Object> l10nParams() {
- return l10nParams;
+ public Object[] l10nParams() {
+ if (l10nParams == null) {
+ return new Object[0];
+ } else {
+ return Arrays.copyOf(l10nParams, l10nParams.length);
+ }
}
}
import org.sonar.server.qualitygate.ws.QgateAppHandler;
import org.sonar.server.qualitygate.ws.QualityGatesWs;
import org.sonar.server.qualityprofile.*;
+import org.sonar.server.qualityprofile.ws.QProfileBackupWsHandler;
+import org.sonar.server.qualityprofile.ws.QProfilesWs;
import org.sonar.server.rule.*;
import org.sonar.server.rule.ws.*;
import org.sonar.server.source.CodeColorizers;
pico.addSingleton(QProfileBackup.class);
pico.addSingleton(QProfileRepositoryExporter.class);
pico.addSingleton(ESActiveRule.class);
+ pico.addSingleton(QProfileBackupWsHandler.class);
+ pico.addSingleton(QProfilesWs.class);
// rule
pico.addSingleton(AnnotationRuleParser.class);
private void checkNotAlreadyExists(String name, String language, SqlSession session) {
if (dao.selectByNameAndLanguage(name, language, session) != null) {
- throw BadRequestException.ofL10n("quality_profiles.already_exists");
+ throw BadRequestException.ofL10n("quality_profiles.profile_x_already_exists", name);
}
}
@Override
public void define(Context context) {
NewController controller = context.createController("api/qprofiles")
- .setDescription("Quality profiles");
+ .setDescription("Quality profiles management");
controller.createAction("restore_default")
.setDescription("Restore default profiles")
*/
package org.sonar.server.ws;
-import org.apache.commons.lang.StringUtils;
import org.elasticsearch.common.collect.Lists;
import org.picocontainer.Startable;
import org.slf4j.LoggerFactory;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.plugins.MimeTypes;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStreamWriter;
// TODO replace by BadRequestException in Request#mandatoryParam()
sendError(400, e.getMessage(), response);
} catch (BadRequestException e) {
- if (StringUtils.isBlank(e.getMessage())) {
- sendError(e, response);
- } else {
- sendError(e.httpCode(), e.getMessage(), response);
- }
+ sendError(e, response);
} catch (ServerException e) {
// TODO support ServerException l10n messages
sendError(e.httpCode(), e.getMessage(), response);
private void sendError(BadRequestException e, ServletResponse response) {
Collection<String> messages = Lists.newArrayList();
- for (Message message: e.errors()) {
- messages.add(i18n.message(Locale.getDefault(), message.l10nKey(), message.text(), message.l10nParams()));
+ if (e.getMessage()!= null || e.l10nKey() != null) {
+ messages.add(message(e.getMessage(), e.l10nKey(), e.l10nParams()));
+ }
+ for (Message message : e.errors()) {
+ messages.add(message(message.text(), message.l10nKey(), message.l10nParams()));
}
sendErrors(response, e.httpCode(), messages.toArray(new String[0]));
}
+ @CheckForNull
+ private String message(@Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams){
+ if (l10nKey != null) {
+ return i18n.message(Locale.getDefault(), l10nKey, message, l10nParams);
+ } else {
+ return message;
+ }
+ }
+
private void sendError(int status, String message, ServletResponse response) {
sendErrors(response, status, message);
}
try {
json.beginObject();
json.name("errors").beginArray();
- for (String message: errors) {
+ for (String message : errors) {
json.beginObject().prop("msg", message).endObject();
}
json.endArray();
fail();
} catch (BadRequestException e) {
assertThat(e.l10nKey()).isEqualTo("errors.is_already_used");
- assertThat(e.l10nParams().iterator().next()).isEqualTo("Compilation");
+ assertThat(e.l10nParams()[0]).isEqualTo("Compilation");
}
}
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
- assertThat(badRequestException.l10nParams().toArray()[0]).isEqualTo("abc");
+ assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
}
}
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
- assertThat(badRequestException.l10nParams().toArray()[0]).isEqualTo("abc");
+ assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
}
}
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
- assertThat(badRequestException.l10nParams().toArray()[0]).isEqualTo("abc");
+ assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
}
}
} catch (Exception e) {
assertThat(e).isInstanceOf(BadRequestException.class);
BadRequestException badRequestException = (BadRequestException) e;
- assertThat(badRequestException.l10nParams().toArray()[0]).isEqualTo("abc");
- assertThat(badRequestException.l10nParams().toArray()[1]).isEqualTo("a, b, c");
+ assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
+ assertThat(badRequestException.l10nParams()[1]).isEqualTo("a, b, c");
}
}
import java.util.Map;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
}
+ @Test
+ public void bad_request_with_i18n_message() throws Exception {
+ InternalRequest request = new SimpleRequest().setParam("count", "3");
+ ServletResponse response = new ServletResponse();
+ when(i18n.message(eq(Locale.getDefault()), eq("bad.request.reason"), anyString(), eq(0))).thenReturn("Bad request reason #0");
+
+ engine.execute(request, response, "api/system", "fail_with_i18n_message");
+
+ assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ + "{\"msg\":\"Bad request reason #0\"}"
+ + "]}");
+ assertThat(response.stream().httpStatus()).isEqualTo(400);
+ assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
+ }
+
@Test
public void bad_request_with_multiple_messages() throws Exception {
InternalRequest request = new SimpleRequest().setParam("count", "3");
ServletResponse response = new ServletResponse();
+
+ engine.execute(request, response, "api/system", "fail_with_multiple_messages");
+
+ assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ + "{\"msg\":\"Bad request reason #0\"},"
+ + "{\"msg\":\"Bad request reason #1\"},"
+ + "{\"msg\":\"Bad request reason #2\"}"
+ + "]}");
+ assertThat(response.stream().httpStatus()).isEqualTo(400);
+ assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
+ }
+
+ @Test
+ public void bad_request_with_multiple_i18n_messages() throws Exception {
+ InternalRequest request = new SimpleRequest().setParam("count", "3");
+ ServletResponse response = new ServletResponse();
when(i18n.message(Locale.getDefault(), "bad.request.reason", null, 0)).thenReturn("Bad request reason #0");
when(i18n.message(Locale.getDefault(), "bad.request.reason", null, 1)).thenReturn("Bad request reason #1");
when(i18n.message(Locale.getDefault(), "bad.request.reason", null, 2)).thenReturn("Bad request reason #2");
- engine.execute(request, response, "api/system", "fail");
+ engine.execute(request, response, "api/system", "fail_with_multiple_i18n_messages");
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ "{\"msg\":\"Bad request reason #0\"},"
.setHandler(new RequestHandler() {
@Override
public void handle(Request request, Response response) {
- if (request.param("count") != null) {
- List<BadRequestException.Message> errors = Lists.newArrayList();
- for (int count=0; count < Integer.valueOf(request.param("count")); count ++) {
- errors.add(Message.ofL10n("bad.request.reason", count));
- }
- throw BadRequestException.of(errors);
- }
throw new IllegalStateException("Unexpected");
}
});
+ newController.createAction("fail_with_i18n_message")
+ .setHandler(new RequestHandler() {
+ @Override
+ public void handle(Request request, Response response) {
+ throw BadRequestException.ofL10n("bad.request.reason", 0);
+ }
+ });
+ newController.createAction("fail_with_multiple_messages")
+ .setHandler(new RequestHandler() {
+ @Override
+ public void handle(Request request, Response response) {
+ List<BadRequestException.Message> errors = Lists.newArrayList();
+ for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
+ errors.add(Message.of("Bad request reason #" + count));
+ }
+ throw BadRequestException.of(errors);
+ }
+ });
+ newController.createAction("fail_with_multiple_i18n_messages")
+ .setHandler(new RequestHandler() {
+ @Override
+ public void handle(Request request, Response response) {
+ List<BadRequestException.Message> errors = Lists.newArrayList();
+ for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
+ errors.add(Message.ofL10n("bad.request.reason", count));
+ }
+ throw BadRequestException.of(errors);
+ }
+ });
newController.createAction("alive")
- .setHandler(new RequestHandler() {
- @Override
- public void handle(Request request, Response response) {
- response.noContent();
- }
- });
+ .setHandler(new RequestHandler() {
+ @Override
+ public void handle(Request request, Response response) {
+ response.noContent();
+ }
+ });
// parameter "message" is required but not "author"
newController.createAction("print")
public void handle(Request request, Response response) {
try {
IOUtils.write(
- request.mandatoryParam("message") + " by " + request.param("author", "-"), response.stream().output());
+ request.mandatoryParam("message") + " by " + request.param("author", "-"), response.stream().output());
} catch (IOException e) {
throw new IllegalStateException(e);
}
*/
package org.sonar.wsclient;
-import org.sonar.wsclient.qualitygate.internal.DefaultQualityGateClient;
-
-import org.sonar.wsclient.qualitygate.QualityGateClient;
import org.sonar.wsclient.internal.HttpRequestFactory;
import org.sonar.wsclient.issue.ActionPlanClient;
import org.sonar.wsclient.issue.IssueClient;
import org.sonar.wsclient.permissions.internal.DefaultPermissionClient;
import org.sonar.wsclient.project.ProjectClient;
import org.sonar.wsclient.project.internal.DefaultProjectClient;
+import org.sonar.wsclient.qprofile.QProfileClient;
+import org.sonar.wsclient.qprofile.internal.DefaultQProfileClient;
+import org.sonar.wsclient.qualitygate.QualityGateClient;
+import org.sonar.wsclient.qualitygate.internal.DefaultQualityGateClient;
import org.sonar.wsclient.rule.RuleClient;
import org.sonar.wsclient.rule.RuleTagClient;
import org.sonar.wsclient.rule.internal.DefaultRuleClient;
return new DefaultQualityGateClient(requestFactory);
}
+ /**
+ * New client to interact with web services related to quality profilesgates
+ */
+ public QProfileClient qProfileClient() {
+ return new DefaultQProfileClient(requestFactory);
+ }
+
+
public SystemClient systemClient() {
return new DefaultSystemClient(requestFactory);
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.wsclient.qprofile;
+
+
+/**
+ * @since 4.4
+ */
+public interface QProfileClient {
+
+ QProfileResult restoreDefault(String language);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.wsclient.qprofile;
+
+import java.util.List;
+
+public interface QProfileResult {
+
+ List<String> infos();
+
+ List<String> warnings();
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.wsclient.qprofile.internal;
+
+import org.json.simple.JSONValue;
+import org.sonar.wsclient.internal.HttpRequestFactory;
+import org.sonar.wsclient.qprofile.QProfileClient;
+import org.sonar.wsclient.qprofile.QProfileResult;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class DefaultQProfileClient implements QProfileClient {
+
+ private final HttpRequestFactory requestFactory;
+
+ public DefaultQProfileClient(HttpRequestFactory requestFactory) {
+ this.requestFactory = requestFactory;
+ }
+
+ @Override
+ public QProfileResult restoreDefault(String language) {
+ String json = requestFactory.post("/api/qprofiles/restore_default", Collections.singletonMap("language", (Object) language));
+ Map jsonRoot = (Map) JSONValue.parse(json);
+ return new DefaultQProfileResult(jsonRoot);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.wsclient.qprofile.internal;
+
+import org.sonar.wsclient.qprofile.QProfileResult;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class DefaultQProfileResult implements QProfileResult {
+
+ private Map json;
+
+ DefaultQProfileResult(Map json) {
+ this.json = json;
+ }
+
+ @Override
+ public List<String> infos() {
+ List<String> infos = new ArrayList<String>();
+ List<String> jsonInfos = (List<String>) json.get("infos");
+ if (jsonInfos != null) {
+ for (String info : jsonInfos) {
+ infos.add(info);
+ }
+ }
+ return infos;
+ }
+
+ @Override
+ public List<String> warnings() {
+ List<String> warnings = new ArrayList<String>();
+ List<String> jsonWarnings = (List<String>) json.get("warnings");
+ if (jsonWarnings != null) {
+ for (String warning : jsonWarnings) {
+ warnings.add(warning);
+ }
+ }
+ return warnings;
+ }
+
+}
import org.sonar.wsclient.issue.internal.DefaultIssueClient;
import org.sonar.wsclient.permissions.internal.DefaultPermissionClient;
import org.sonar.wsclient.project.internal.DefaultProjectClient;
+import org.sonar.wsclient.qprofile.internal.DefaultQProfileClient;
+import org.sonar.wsclient.qualitygate.internal.DefaultQualityGateClient;
+import org.sonar.wsclient.rule.internal.DefaultRuleClient;
+import org.sonar.wsclient.rule.internal.DefaultRuleTagClient;
import org.sonar.wsclient.system.internal.DefaultSystemClient;
import org.sonar.wsclient.user.internal.DefaultUserClient;
assertThat(client.userClient()).isNotNull().isInstanceOf(DefaultUserClient.class);
assertThat(client.permissionClient()).isNotNull().isInstanceOf(DefaultPermissionClient.class);
assertThat(client.projectClient()).isNotNull().isInstanceOf(DefaultProjectClient.class);
+ assertThat(client.ruleTagClient()).isNotNull().isInstanceOf(DefaultRuleTagClient.class);
+ assertThat(client.ruleClient()).isNotNull().isInstanceOf(DefaultRuleClient.class);
+ assertThat(client.qualityGateClient()).isNotNull().isInstanceOf(DefaultQualityGateClient.class);
+ assertThat(client.qProfileClient()).isNotNull().isInstanceOf(DefaultQProfileClient.class);
assertThat(client.systemClient()).isNotNull().isInstanceOf(DefaultSystemClient.class);
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.wsclient.qprofile.internal;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.wsclient.MockHttpServerInterceptor;
+import org.sonar.wsclient.internal.HttpRequestFactory;
+import org.sonar.wsclient.qprofile.QProfileResult;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.MapAssert.entry;
+
+public class DefaultQProfileClientTest {
+
+ @Rule
+ public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor();
+
+ @Test
+ public void restore_default_profiles() {
+ HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url());
+
+ httpServer.stubResponseBody("{\"infos\":[\"Some info\"],\"warnings\":[\"Some warnings\"]}");
+
+ DefaultQProfileClient client = new DefaultQProfileClient(requestFactory);
+ QProfileResult result = client.restoreDefault("java");
+
+ assertThat(httpServer.requestedPath()).isEqualTo("/api/qprofiles/restore_default");
+ assertThat(httpServer.requestParams()).includes(
+ entry("language", "java")
+ );
+ assertThat(result).isNotNull();
+ assertThat(result.infos()).containsOnly("Some info");
+ assertThat(result.warnings()).containsOnly("Some warnings");
+ }
+
+}