]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5007 improve l10n of server exception handling
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 16 Jun 2014 12:21:25 +0000 (14:21 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 16 Jun 2014 12:30:43 +0000 (14:30 +0200)
44 files changed:
sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java
sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java
sonar-server/src/main/java/org/sonar/server/exceptions/BadRequestException.java
sonar-server/src/main/java/org/sonar/server/exceptions/Errors.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/exceptions/Message.java
sonar-server/src/main/java/org/sonar/server/exceptions/Messages.java [deleted file]
sonar-server/src/main/java/org/sonar/server/exceptions/ServerException.java
sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeQuery.java
sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/BulkChangeResult.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileRestoreBuiltInAction.java
sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java
sonar-server/src/main/java/org/sonar/server/util/BooleanTypeValidation.java
sonar-server/src/main/java/org/sonar/server/util/FloatTypeValidation.java
sonar-server/src/main/java/org/sonar/server/util/IntegerTypeValidation.java
sonar-server/src/main/java/org/sonar/server/util/StringListTypeValidation.java
sonar-server/src/main/java/org/sonar/server/util/TypeValidation.java
sonar-server/src/main/java/org/sonar/server/util/TypeValidations.java
sonar-server/src/main/java/org/sonar/server/util/Validation.java
sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java
sonar-server/src/test/java/org/sonar/server/debt/DebtModelOperationsTest.java
sonar-server/src/test/java/org/sonar/server/exceptions/BadRequestExceptionTest.java
sonar-server/src/test/java/org/sonar/server/exceptions/ServerExceptionTest.java
sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeQueryTest.java
sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QGatesWsTest.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileRestoreBuiltInActionTest.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java
sonar-server/src/test/java/org/sonar/server/util/BooleanTypeValidationTest.java
sonar-server/src/test/java/org/sonar/server/util/FloatTypeValidationTest.java
sonar-server/src/test/java/org/sonar/server/util/IntegerTypeValidationTest.java
sonar-server/src/test/java/org/sonar/server/util/StringListTypeValidationTest.java
sonar-server/src/test/java/org/sonar/server/util/TypeValidationsTest.java
sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java

index ace86157de141e23d2b96699b8515ec7fa4dc8b7..94de74f57e41af0dd5926600b5f53e5f8c6543f3 100644 (file)
@@ -75,7 +75,7 @@ public class DefaultRubyComponentService implements RubyComponentService {
         .setCreatedAt(new Date()));
     component = (ComponentDto) resourceDao.findByKey(kee);
     if (component == null) {
-      throw new BadRequestException(String.format("%s not created: %s", null, kee));
+      throw new BadRequestException(String.format("Component not created: %s", kee));
     }
     resourceIndexerDao.indexResource(component.getId());
     return component.getId();
index 5773eb9dcf446b79809ca7c7f08e3c938cac7b66..fcb32e591e83b3905e386c2212cf0d67fa81c897 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.server.util.Validation;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+
 import java.util.Date;
 import java.util.List;
 
@@ -253,7 +254,7 @@ public class DebtModelOperations implements ServerComponent {
 
   private void checkNotAlreadyExists(String name, SqlSession session) {
     if (dbClient.debtCharacteristicDao().selectByName(name, session) != null) {
-      throw BadRequestException.ofL10n(Validation.IS_ALREADY_USED_MESSAGE, name);
+      throw new BadRequestException(Validation.IS_ALREADY_USED_MESSAGE, name);
     }
   }
 
index 27e6c2f14530a714841aac1013d79f60c40ca027..22f224b3d6f4d6fb084dabf8aa4aec15a481bf05 100644 (file)
  */
 package org.sonar.server.exceptions;
 
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import com.google.common.base.Objects;
+import org.sonar.api.utils.ValidationMessages;
 
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
 import java.util.List;
 
-import static com.google.common.collect.Lists.newArrayList;
-
 /**
  * Request is not valid and can not be processed.
  */
@@ -36,127 +31,48 @@ public class BadRequestException extends ServerException {
 
   private static final int BAD_REQUEST = 400;
 
-  private final List<Message> errors;
-
-  public BadRequestException(String message) {
-    super(BAD_REQUEST, message);
-    this.errors = newArrayList();
-  }
-
-  public BadRequestException(String message, List<Message> errors) {
-    super(BAD_REQUEST, message);
-    this.errors = errors;
-  }
+  private final Errors errors;
 
-  public BadRequestException(@Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams) {
-    super(BAD_REQUEST, message, l10nKey, l10nParams);
-    this.errors = newArrayList();
+  public BadRequestException(String l10nKey, Object... l10nParams) {
+    super(BAD_REQUEST);
+    this.errors = new Errors().add(Message.of(l10nKey, l10nParams));
   }
 
-  public BadRequestException(@Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams, List<Message> errors) {
-    super(BAD_REQUEST, message, l10nKey, l10nParams);
-    this.errors = errors;
+  public BadRequestException(List<Message> messages) {
+    super(BAD_REQUEST);
+    this.errors = new Errors().add(messages);
   }
 
-  public static BadRequestException of(String message) {
-    return new BadRequestException(message);
+  public BadRequestException(Errors e) {
+    super(BAD_REQUEST);
+    this.errors = e;
   }
 
-  public static BadRequestException of(String message, List<Message> errors) {
-    return new BadRequestException(message, errors);
+  public BadRequestException(ValidationMessages validationMessages) {
+    super(BAD_REQUEST);
+    this.errors = new Errors();
+    for (String s : validationMessages.getErrors()) {
+      errors.add(Message.of(s));
+    }
   }
 
-  public static BadRequestException of(List<Message> errors) {
-    return new BadRequestException(null, null, null, errors);
+  public Errors errors() {
+    return errors;
   }
 
-  public static BadRequestException ofL10n(String l10nKey, Object... l10nParams) {
-    return new BadRequestException(null, l10nKey, l10nParams);
+  public Message firstError() {
+    return errors.messages().get(0);
   }
 
-  public static BadRequestException ofL10n(List<Message> errors, String l10nKey, Object... l10nParams) {
-    return new BadRequestException(null, l10nKey, l10nParams, errors);
+  @Override
+  public String getMessage() {
+    return firstError().getKey();
   }
 
-  /**
-   * List of error messages. Empty if there are no errors.
-   */
-  public List<Message> errors() {
-    return errors;
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("errors", errors)
+      .toString();
   }
-
-  public static class Message {
-    private final String l10nKey;
-    private final Object[] l10nParams;
-    private final String text;
-
-    private Message(@Nullable String l10nKey, @Nullable Object[] l10nParams, @Nullable String text) {
-      this.l10nKey = l10nKey;
-      this.l10nParams = l10nParams;
-      this.text = text;
-    }
-
-    public static Message of(String text) {
-      return new Message(null, null, text);
-    }
-
-    public static Message ofL10n(String l10nKey, Object... l10nParams) {
-      return new Message(l10nKey, l10nParams, null);
-    }
-
-    @CheckForNull
-    public String text() {
-      return text;
-    }
-
-    @CheckForNull
-    public String l10nKey() {
-      return l10nKey;
-    }
-
-    public Object[] l10nParams() {
-      if (l10nParams == null) {
-        return new Object[0];
-      } else {
-        return Arrays.copyOf(l10nParams, l10nParams.length);
-      }
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      Message message = (Message) o;
-
-      if (l10nKey != null ? !l10nKey.equals(message.l10nKey) : message.l10nKey != null) {
-        return false;
-      }
-      // Probably incorrect - comparing Object[] arrays with Arrays.equals
-      if (!Arrays.equals(l10nParams, message.l10nParams)) {
-        return false;
-      }
-      if (text != null ? !text.equals(message.text) : message.text != null) {
-        return false;
-      }
-      return true;
-    }
-
-    @Override
-    public int hashCode() {
-      int result = l10nKey != null ? l10nKey.hashCode() : 0;
-      result = 31 * result + (l10nParams != null ? Arrays.hashCode(l10nParams) : 0);
-      result = 31 * result + (text != null ? text.hashCode() : 0);
-      return result;
-    }
-
-    @Override
-    public String toString() {
-      return new ReflectionToStringBuilder(this).toString();
-    }
-  }
-
 }
diff --git a/sonar-server/src/main/java/org/sonar/server/exceptions/Errors.java b/sonar-server/src/main/java/org/sonar/server/exceptions/Errors.java
new file mode 100644 (file)
index 0000000..0cdee46
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.exceptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.utils.text.JsonWriter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+public class Errors {
+
+  private final List<Message> messages = Lists.newArrayList();
+
+  public Errors() {
+  }
+
+  public Errors add(Errors errors) {
+    this.messages.addAll(errors.messages());
+    return this;
+  }
+
+  public Errors add(Collection<Message> messages) {
+    for (Message message : messages) {
+      add(message);
+    }
+    return this;
+  }
+
+  public Errors add(Message message, Message... others) {
+    messages.add(message);
+    Collections.addAll(messages, others);
+    return this;
+  }
+
+  public List<Message> messages() {
+    return messages;
+  }
+
+  public boolean isEmpty() {
+    return messages.isEmpty();
+  }
+
+  public boolean check(boolean expression, String l10nKey, Object... l10nParams) {
+    if (!expression) {
+      add(Message.of(l10nKey, l10nParams));
+    }
+    return expression;
+  }
+
+  public void writeJson(JsonWriter json, I18n i18n, Locale locale) {
+    writeJson(json, i18n, locale, "errors");
+  }
+
+  public void writeJsonAsWarnings(JsonWriter json, I18n i18n, Locale locale) {
+    writeJson(json, i18n, locale, "warnings");
+  }
+
+  private void writeJson(JsonWriter json, I18n i18n, Locale locale, String name) {
+    if (!messages.isEmpty()) {
+      json.name(name).beginArray();
+      for (Message message : messages) {
+        json.beginObject();
+        String text = StringUtils.defaultString(i18n.message(locale, message.getKey(), message.getKey(), message.getParams()), message.getKey());
+        json.prop("msg", text);
+        json.endObject();
+      }
+      json.endArray();
+    }
+  }
+
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("messages", messages)
+      .toString();
+  }
+}
index 5a332610ba511b37118f4e8f3788899bfb3a97f3..0882de85f196c9a9687631d57d43bcae75f00e17 100644 (file)
 package org.sonar.server.exceptions;
 
 import com.google.common.base.Objects;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Map;
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang.StringUtils;
 
 public class Message {
 
-  public static enum Level {
-    INFO, WARNING, ERROR
-  }
-
-  private final String code;
-  private String label;
-  private Object[] l10nParams = new Object[0];
-  private Level level;
-  private Map<String, Object> params;
-
-  private Message(String code) {
-    this.code = code;
-  }
-
-  public String getCode() {
-    return code;
-  }
-@CheckForNull
-  public String getLabel() {
-    return label;
-  }
-
-  public Message setLabel(String s) {
-    this.label = s;
-    return this;
-  }
-
-  public Object[] getL10nParams() {
-    return l10nParams;
-  }
+  private final String key;
+  private final Object[] params;
 
-  public Message setL10nParams(Object[] l10nParams) {
-    this.l10nParams = l10nParams;
-    return this;
-  }
-
-  public Level getLevel() {
-    return level;
-  }
-
-  public Message setLevel(Level level) {
-    this.level = level;
-    return this;
-  }
-
-  public Map<String, Object> getParams() {
-    return params;
-  }
-
-  public Message setParams(Map<String, Object> params) {
+  private Message(String key, Object[] params) {
+    this.key = key;
     this.params = params;
-    return this;
   }
 
-  public Message setParam(String key, @Nullable Object value) {
-    this.params.put(key, value);
-    return this;
+  public String getKey() {
+    return key;
   }
 
-  public static Message newError(String code) {
-    return new Message(code).setLevel(Level.ERROR);
-  }
-
-  public static Message newWarning(String code) {
-    return new Message(code).setLevel(Level.WARNING);
+  public Object[] getParams() {
+    return params;
   }
 
-  public static Message newInfo(String code) {
-    return new Message(code).setLevel(Level.INFO);
+  public static Message of(String l10nKey, Object... l10nParams) {
+    Preconditions.checkArgument(StringUtils.isNotBlank(l10nKey));
+    return new Message(l10nKey, l10nParams);
   }
 
   @Override
   public String toString() {
     return Objects.toStringHelper(this)
-      .add("code", code)
-      .add("label", label)
-      .add("l10nParams", l10nParams)
-      .add("level", level)
+      .add("key", key)
       .add("params", params)
       .toString();
   }
diff --git a/sonar-server/src/main/java/org/sonar/server/exceptions/Messages.java b/sonar-server/src/main/java/org/sonar/server/exceptions/Messages.java
deleted file mode 100644 (file)
index 89a68ca..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.exceptions;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ListMultimap;
-import org.sonar.api.utils.text.JsonWriter;
-
-import java.util.Collection;
-import java.util.List;
-
-public class Messages {
-
-  private ListMultimap<Message.Level, Message> messagesByLevel = ArrayListMultimap.create();
-
-  public Messages add(Message message) {
-    messagesByLevel.put(message.getLevel(), message);
-    return this;
-  }
-
-  public Collection<Message> all() {
-    return messagesByLevel.values();
-  }
-
-  public List<Message> getByLevel(Message.Level level) {
-    return messagesByLevel.get(level);
-  }
-
-  public boolean hasLevel(Message.Level level) {
-    return messagesByLevel.containsKey(level);
-  }
-
-  public void writeJson(JsonWriter json) {
-    writeJson(json, "errors", Message.Level.ERROR);
-    writeJson(json, "warnings", Message.Level.WARNING);
-    writeJson(json, "infos", Message.Level.INFO);
-  }
-
-  private void writeJson(JsonWriter json, String label, Message.Level level) {
-    List<Message> messages = messagesByLevel.get(level);
-    if (!messages.isEmpty()) {
-      json.name(label).beginArray();
-      for (Message message : messages) {
-        json.beginObject().prop("msg", message.getLabel()).endObject();
-      }
-      json.endArray();
-    }
-  }
-}
index 2dfd845e75872293fd122742d8464c485ae8adb7..bce33f965ca8333be7e9c022286a165ab3ed6266 100644 (file)
  */
 package org.sonar.server.exceptions;
 
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
-
 public class ServerException extends RuntimeException {
   private final int httpCode;
 
-  private final String l10nKey;
-  private final Object[] l10nParams;
-
   public ServerException(int httpCode) {
     this.httpCode = httpCode;
-    this.l10nKey = null;
-    this.l10nParams = null;
   }
 
   public ServerException(int httpCode, String message) {
     super(message);
     this.httpCode = httpCode;
-    this.l10nKey = null;
-    this.l10nParams = null;
-  }
-
-  public ServerException(int httpCode, @Nullable String message, @Nullable String l10nKey, @Nullable Object[] l10nParams) {
-    super(message);
-    this.httpCode = httpCode;
-    this.l10nKey = l10nKey;
-    this.l10nParams = l10nParams;
   }
 
   public int httpCode() {
     return httpCode;
   }
-
-  @CheckForNull
-  public String l10nKey() {
-    return l10nKey;
-  }
-
-  @CheckForNull
-  public Object[] l10nParams() {
-    if (l10nParams == null) {
-      return new Object[0];
-    } else {
-      return Arrays.copyOf(l10nParams, l10nParams.length);
-    }
-  }
 }
diff --git a/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java b/sonar-server/src/main/java/org/sonar/server/exceptions/Verifications.java
new file mode 100644 (file)
index 0000000..d865ab2
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.exceptions;
+
+public class Verifications {
+
+  private Verifications() {
+    // only static stuff
+  }
+
+  public static void check(boolean expression, String l10nKey, Object... l10nParams) {
+    if (!expression) {
+      throw new BadRequestException(l10nKey, l10nParams);
+    }
+  }
+}
index 0ccfca938c28a30605b364419172084907d0b064..9ed1662e7467838d48b702be90e5515cbfb30a8b 100644 (file)
@@ -615,7 +615,7 @@ public class InternalRubyIssueService implements ServerComponent {
 
   private void checkOptionalSizeParameter(String value, String paramName, Integer size) {
     if (!Strings.isNullOrEmpty(value) && value.length() > size) {
-      throw BadRequestException.ofL10n(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
+      throw new BadRequestException(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
     }
   }
 
index aa7f17c020ba1fea07e5473935a393596312a24d..2dff217866e6ae7fa9fa111fcd26d1a7558ba502 100644 (file)
@@ -62,14 +62,14 @@ public class IssueBulkChangeQuery {
     parse(props, null);
   }
 
-  private void parse(Map<String, Object> props, String comment) {
+  private void parse(Map<String, Object> props, @Nullable String comment) {
     this.issues = sanitizeList(RubyUtils.toStrings(props.get("issues")));
     if (issues == null || issues.isEmpty()) {
-      throw BadRequestException.ofL10n("issue_bulk_change.error.empty_issues");
+      throw new BadRequestException("issue_bulk_change.error.empty_issues");
     }
     actions = sanitizeList(RubyUtils.toStrings(props.get("actions")));
     if (actions == null || actions.isEmpty()) {
-      throw BadRequestException.ofL10n("issue_bulk_change.error.need_one_action");
+      throw new BadRequestException("issue_bulk_change.error.need_one_action");
     }
     for (String action : actions) {
       Map<String, Object> actionProperties = getActionProps(action, props);
@@ -83,7 +83,7 @@ public class IssueBulkChangeQuery {
     }
   }
 
-  private List<String> sanitizeList(List<String> list) {
+  private List<String> sanitizeList(@Nullable List<String> list) {
     if (list == null || list.isEmpty()) {
       return Collections.emptyList();
     }
index 7117afc7a0b36937f9c1e5c47869e5d8d8e5ceff..924eb4a914cd4e05943b8311faaaefe544a012bd 100644 (file)
@@ -40,7 +40,8 @@ import org.sonar.core.qualitygate.db.QualityGateDao;
 import org.sonar.core.qualitygate.db.QualityGateDto;
 import org.sonar.server.component.persistence.ComponentDao;
 import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.BadRequestException.Message;
+import org.sonar.server.exceptions.Errors;
+import org.sonar.server.exceptions.Message;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.ServerException;
 import org.sonar.server.user.UserSession;
@@ -50,10 +51,6 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
 
 /**
  * @since 4.3
@@ -75,7 +72,7 @@ public class QualityGates {
   private final MyBatis myBatis;
 
   public QualityGates(QualityGateDao dao, QualityGateConditionDao conditionDao, MetricFinder metricFinder, PropertiesDao propertiesDao, ComponentDao componentDao,
-                      MyBatis myBatis) {
+    MyBatis myBatis) {
     this.dao = dao;
     this.conditionDao = conditionDao;
     this.metricFinder = metricFinder;
@@ -119,10 +116,10 @@ public class QualityGates {
       dao.insert(destinationGate, session);
       for (QualityGateConditionDto sourceCondition : conditionDao.selectForQualityGate(sourceId, session)) {
         conditionDao.insert(new QualityGateConditionDto().setQualityGateId(destinationGate.getId())
-            .setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
-            .setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
+          .setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
+          .setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
           session
-        );
+          );
       }
       session.commit();
     } finally {
@@ -131,7 +128,6 @@ public class QualityGates {
     return destinationGate;
   }
 
-
   public Collection<QualityGateDto> list() {
     return dao.selectAll();
   }
@@ -173,7 +169,7 @@ public class QualityGates {
   }
 
   public QualityGateConditionDto createCondition(long qGateId, String metricKey, String operator,
-                                                 @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
+    @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
     checkPermission(UserSession.get());
     getNonNullQgate(qGateId);
     Metric metric = getNonNullMetric(metricKey);
@@ -186,7 +182,7 @@ public class QualityGates {
   }
 
   public QualityGateConditionDto updateCondition(long condId, String metricKey, String operator,
-                                                 @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
+    @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
     checkPermission(UserSession.get());
     QualityGateConditionDto condition = getNonNullCondition(condId);
     Metric metric = getNonNullMetric(metricKey);
@@ -257,42 +253,36 @@ public class QualityGates {
   }
 
   private void validateCondition(Metric metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
-    List<Message> validationMessages = newArrayList();
-    validateMetric(metric, validationMessages);
-    validateOperator(metric, operator, validationMessages);
-    validateThresholds(warningThreshold, errorThreshold, validationMessages);
-    validatePeriod(metric, period, validationMessages);
-    if (!validationMessages.isEmpty()) {
-      throw BadRequestException.of(validationMessages);
+    Errors errors = new Errors();
+    validateMetric(metric, errors);
+    checkOperator(metric, operator, errors);
+    checkThresholds(warningThreshold, errorThreshold, errors);
+    checkPeriod(metric, period, errors);
+    if (!errors.isEmpty()) {
+      throw new BadRequestException(errors);
     }
   }
 
-  private void validatePeriod(Metric metric, @Nullable Integer period, List<Message> validationMessages) {
+  private void checkPeriod(Metric metric, @Nullable Integer period, Errors errors) {
     if (period == null) {
-      if (metric.getKey().startsWith("new_")) {
-        validationMessages.add(Message.of("A period must be selected for differential metrics."));
-      }
-    } else if (period < 1 || period > 5) {
-      validationMessages.add(Message.of("Valid periods are integers between 1 and 5 (included)."));
+      errors.check(!metric.getKey().startsWith("new_"), "A period must be selected for differential metrics.");
+
+    } else {
+      errors.check(period >= 1 && period <= 5, "Valid periods are integers between 1 and 5 (included).");
     }
   }
 
-  private void validateThresholds(@Nullable String warningThreshold, @Nullable String errorThreshold, List<Message> validationMessages) {
-    if (warningThreshold == null && errorThreshold == null) {
-      validationMessages.add(Message.of("At least one threshold (warning, error) must be set."));
-    }
+  private void checkThresholds(@Nullable String warningThreshold, @Nullable String errorThreshold, Errors errors) {
+    errors.check(warningThreshold != null || errorThreshold != null, "At least one threshold (warning, error) must be set.");
   }
 
-  private void validateOperator(Metric metric, String operator, List<Message> validationMessages) {
-    if (!QualityGateConditionDto.isOperatorAllowed(operator, metric.getType())) {
-      validationMessages.add(Message.of(String.format("Operator %s is not allowed for metric type %s.", operator, metric.getType())));
-    }
+  private void checkOperator(Metric metric, String operator, Errors errors) {
+    errors
+      .check(QualityGateConditionDto.isOperatorAllowed(operator, metric.getType()), String.format("Operator %s is not allowed for metric type %s.", operator, metric.getType()));
   }
 
-  private void validateMetric(Metric metric, List<Message> validationMessages) {
-    if (!isAlertable(metric)) {
-      validationMessages.add(Message.of(String.format("Metric '%s' cannot be used to define a condition.", metric.getKey())));
-    }
+  private void validateMetric(Metric metric, Errors errors) {
+    errors.check(isAlertable(metric), String.format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
   }
 
   private boolean isAvailableForInit(Metric metric) {
@@ -355,24 +345,22 @@ public class QualityGates {
   }
 
   private void validateQualityGate(@Nullable Long updatingQgateId, @Nullable String name) {
-    List<BadRequestException.Message> messages = newArrayList();
+    Errors errors = new Errors();
     if (Strings.isNullOrEmpty(name)) {
-      messages.add(BadRequestException.Message.ofL10n(Validation.CANT_BE_EMPTY_MESSAGE, "Name"));
+      errors.add(Message.of(Validation.CANT_BE_EMPTY_MESSAGE, "Name"));
     } else {
-      messages.addAll(checkQgateNotAlreadyExists(updatingQgateId, name));
+      checkQgateNotAlreadyExists(updatingQgateId, name, errors);
     }
-    if (!messages.isEmpty()) {
-      throw BadRequestException.of(messages);
+    if (!errors.isEmpty()) {
+      throw new BadRequestException(errors);
     }
   }
 
-  private Collection<BadRequestException.Message> checkQgateNotAlreadyExists(@Nullable Long updatingQgateId, String name) {
+  private void checkQgateNotAlreadyExists(@Nullable Long updatingQgateId, String name, Errors errors) {
     QualityGateDto existingQgate = dao.selectByName(name);
     boolean isModifyingCurrentQgate = updatingQgateId != null && existingQgate != null && existingQgate.getId().equals(updatingQgateId);
-    if (!isModifyingCurrentQgate && existingQgate != null) {
-      return Collections.singleton(BadRequestException.Message.ofL10n(Validation.IS_ALREADY_USED_MESSAGE, "Name"));
-    }
-    return Collections.emptySet();
+    errors.check(isModifyingCurrentQgate || existingQgate == null, Validation.IS_ALREADY_USED_MESSAGE, "Name");
+
   }
 
   private void checkPermission(UserSession userSession) {
index e44abb4a86a312d46b631b57cbe67c936c9b9bf9..8eadf2c012cafd244e18f2975a1e1ef519d5733f 100644 (file)
 package org.sonar.server.qualityprofile;
 
 import com.google.common.collect.Lists;
-import org.sonar.server.exceptions.Message;
-import org.sonar.server.exceptions.Messages;
+import org.sonar.server.exceptions.Errors;
 
 import java.util.Collection;
 import java.util.List;
 
 public class BulkChangeResult {
 
-  private final Messages messages = new Messages();
+  private final Errors errors = new Errors();
   private int succeeded = 0, failed = 0;
   private final List<ActiveRuleChange> changes = Lists.newArrayList();
 
-  BulkChangeResult addMessage(Message message) {
-    this.messages.add(message);
-    return this;
-  }
-
-  public Messages getMessages() {
-    return messages;
+  public Errors getErrors() {
+    return errors;
   }
 
   public int countSucceeded() {
index a9c4ebb17f3d7d4693bb696b326234fe03d4b646..52c1775beda76457ed9ff90408a9dee16be61a49 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.user.UserSession;
 
 import javax.annotation.Nullable;
+
 import java.util.List;
 import java.util.Map;
 
@@ -47,7 +48,7 @@ public class QProfileOperations implements ServerComponent {
   private final QProfileLookup profileLookup;
 
   public QProfileOperations(MyBatis myBatis, QualityProfileDao dao, PropertiesDao propertiesDao,
-                            QProfileRepositoryExporter exporter, PreviewCache dryRunCache, QProfileLookup profileLookup) {
+    QProfileRepositoryExporter exporter, PreviewCache dryRunCache, QProfileLookup profileLookup) {
     this.myBatis = myBatis;
     this.dao = dao;
     this.propertiesDao = propertiesDao;
@@ -128,7 +129,7 @@ public class QProfileOperations implements ServerComponent {
 
   private void checkNotAlreadyExists(String name, String language, DbSession session) {
     if (dao.selectByNameAndLanguage(name, language, session) != null) {
-      throw BadRequestException.ofL10n("quality_profiles.profile_x_already_exists", name);
+      throw new BadRequestException("quality_profiles.profile_x_already_exists", name);
     }
   }
 
index 5a098665cce9d825967b52050b413bb197b7b4e9..d3bdcf5d466319f5f655f01eceffca605d5d7c27 100644 (file)
@@ -68,7 +68,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
   }
 
   public QProfileRepositoryExporter(DatabaseSessionFactory sessionFactory, ActiveRuleDao activeRuleDao,
-                                    List<ProfileImporter> importers, List<ProfileExporter> exporters) {
+    List<ProfileImporter> importers, List<ProfileExporter> exporters) {
     this.sessionFactory = sessionFactory;
     this.activeRuleDao = activeRuleDao;
     this.importers = importers;
@@ -89,7 +89,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
     DatabaseSession session = sessionFactory.getSession();
     RulesProfile rulesProfile = session.getSingleResult(RulesProfile.class, "id", profile.id());
     if (rulesProfile == null) {
-      throw new NotFoundException("This profile does not exists.");
+      throw new NotFoundException("This profile does not exist");
     }
     ProfileExporter exporter = getProfileExporter(pluginKey);
     Writer writer = new StringWriter();
@@ -114,16 +114,12 @@ public class QProfileRepositoryExporter implements ServerComponent {
         paramsByActiveRule.put(activeRuleDto.getId(), activeRuleParamDto);
       }
     }
-    //ruleRegistry.bulkIndexActiveRules(activeRuleDtos, paramsByActiveRule);
+    // TODO ruleRegistry.bulkIndexActiveRules(activeRuleDtos, paramsByActiveRule);
   }
 
   private void processValidationMessages(ValidationMessages messages, QProfileResult result) {
     if (!messages.getErrors().isEmpty()) {
-      List<BadRequestException.Message> errors = newArrayList();
-      for (String error : messages.getErrors()) {
-        errors.add(BadRequestException.Message.of(error));
-      }
-      throw BadRequestException.of("Fail to import profile", errors);
+      throw new BadRequestException(messages);
     }
     result.addWarnings(messages.getWarnings());
     result.addInfos(messages.getInfos());
@@ -154,7 +150,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
         return importer;
       }
     }
-    throw BadRequestException.of("No such importer : " + importerKey);
+    throw new BadRequestException("No such importer : " + importerKey);
   }
 
   private ProfileExporter getProfileExporter(String exporterKey) {
@@ -163,7 +159,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
         return exporter;
       }
     }
-    throw BadRequestException.of("No such exporter : " + exporterKey);
+    throw new BadRequestException("No such exporter : " + exporterKey);
   }
 
   public List<ProfileExporter> getProfileExportersForLanguage(String language) {
index ac11fe27dc56e7e39683acbc3bd7c639e135405f..c664c5b395fa1277d6129171e40ec33e487bfb6b 100644 (file)
@@ -23,7 +23,6 @@ import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.profiles.ProfileDefinition;
 import org.sonar.api.profiles.RulesProfile;
@@ -44,8 +43,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import static com.google.common.collect.Lists.newArrayList;
-
 public class QProfileReset implements ServerComponent {
 
   private final DbClient db;
@@ -121,7 +118,7 @@ public class QProfileReset implements ServerComponent {
           result.addChanges(changes);
         } catch (BadRequestException e) {
           result.incrementFailed();
-          //TODOresult.addMessage()
+          result.getErrors().add(e.errors());
         }
       }
 
@@ -155,12 +152,7 @@ public class QProfileReset implements ServerComponent {
 
   private void processValidationMessages(ValidationMessages messages) {
     if (!messages.getErrors().isEmpty()) {
-      List<BadRequestException.Message> errors = newArrayList();
-      for (String error : messages.getErrors()) {
-        errors.add(BadRequestException.Message.of(error));
-      }
-      throw BadRequestException.of("Fail to restore profile", errors);
+      throw new BadRequestException(messages);
     }
   }
 }
-
index 1e11d2b9296c2f4dbf0f15e8ed387aa5ae78e1a1..cd688a375110e58dfbfead4a8a8d3c27666ee72c 100644 (file)
@@ -147,7 +147,7 @@ public class QProfiles implements ServerComponent {
 
   private void checkProfileNameParam(String name) {
     if (Strings.isNullOrEmpty(name)) {
-      throw BadRequestException.ofL10n("quality_profiles.please_type_profile_name");
+      throw new BadRequestException("quality_profiles.please_type_profile_name");
     }
   }
 
index 06e5be6b99181a9e77f34ca6fcf4fd539ac0b067..1ef15238fe0233f943b1e6eacf7dd6a70246465a 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.qualityprofile.ws;
 
 import org.sonar.api.ServerComponent;
+import org.sonar.api.i18n.I18n;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
@@ -31,6 +32,7 @@ import org.sonar.server.qualityprofile.BulkChangeResult;
 import org.sonar.server.qualityprofile.QProfileService;
 import org.sonar.server.rule.RuleService;
 import org.sonar.server.rule.ws.SearchAction;
+import org.sonar.server.user.UserSession;
 
 public class BulkRuleActivationActions implements ServerComponent {
 
@@ -42,10 +44,12 @@ public class BulkRuleActivationActions implements ServerComponent {
 
   private final QProfileService profileService;
   private final RuleService ruleService;
+  private final I18n i18n;
 
-  public BulkRuleActivationActions(QProfileService profileService, RuleService ruleService) {
+  public BulkRuleActivationActions(QProfileService profileService, RuleService ruleService, I18n i18n) {
     this.profileService = profileService;
     this.ruleService = ruleService;
+    this.i18n = i18n;
   }
 
   void define(WebService.NewController controller) {
@@ -117,7 +121,7 @@ public class BulkRuleActivationActions implements ServerComponent {
     JsonWriter json = response.newJsonWriter().beginObject();
     json.prop("succeeded", result.countSucceeded());
     json.prop("failed", result.countFailed());
-    result.getMessages().writeJson(json);
+    result.getErrors().writeJsonAsWarnings(json, i18n, UserSession.get().locale());
     json.endObject().close();
   }
 
index b3e849494d2d83eb931b61d04e006ee25c9c6da5..1d05d7a645e89ac27cd7da03e671b3ad14cf8543 100644 (file)
@@ -24,8 +24,6 @@ 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.text.JsonWriter;
-import org.sonar.server.qualityprofile.QProfileResult;
 import org.sonar.server.qualityprofile.QProfileService;
 
 public class QProfileRestoreBuiltInAction implements RequestHandler {
@@ -53,31 +51,7 @@ public class QProfileRestoreBuiltInAction implements RequestHandler {
   public void handle(Request request, Response response) {
     String language = request.mandatoryParam("language");
     service.restoreBuiltInProfilesForLanguage(language);
-
-    // TODO
-    QProfileResult result = new QProfileResult();
-
-    if (!result.infos().isEmpty() || !result.warnings().isEmpty()) {
-      JsonWriter json = response.newJsonWriter();
-      json.beginObject();
-      if (!result.infos().isEmpty()) {
-        json.name("infos").beginArray();
-        for (String info : result.infos()) {
-          json.value(info);
-        }
-        json.endArray();
-      }
-      if (!result.warnings().isEmpty()) {
-        json.name("warnings").beginArray();
-        for (String warning : result.warnings()) {
-          json.value(warning);
-        }
-        json.endArray();
-      }
-      json.endObject().close();
-    } else {
-      response.noContent();
-    }
+    response.noContent();
   }
 
 }
index 72ef0af1d8e92d67c429cd9355fce5031ffd3e02..d346638ff21e370c4928b7ac114a8511ce706ec6 100644 (file)
@@ -87,7 +87,7 @@ public class RuleOperations implements ServerComponent {
         session.commit();
       }
     } catch (IllegalArgumentException e) {
-      throw BadRequestException.of(e.getMessage());
+      throw new BadRequestException(e.getMessage());
     } finally {
       MyBatis.closeQuietly(session);
     }
index 39169be427a548e7578504ce59f900ad5b53fa13..53424f2778c0468f93aa67bc268a28d9ae91e33b 100644 (file)
@@ -36,7 +36,7 @@ public class BooleanTypeValidation implements TypeValidation {
   @Override
   public void validate(String value, List<String> options) {
     if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) {
-      throw BadRequestException.ofL10n("errors.type.notBoolean", value);
+      throw new BadRequestException("errors.type.notBoolean", value);
     }
   }
 
index e1ea779e66f1447f94e0efd7a78ff3a063fa4199..c068601bb83120f84ce9b25111e999dde8df883d 100644 (file)
@@ -23,6 +23,7 @@ package org.sonar.server.util;
 import org.sonar.api.PropertyType;
 import org.sonar.server.exceptions.BadRequestException;
 
+import javax.annotation.Nullable;
 import java.util.List;
 
 public class FloatTypeValidation implements TypeValidation {
@@ -33,11 +34,11 @@ public class FloatTypeValidation implements TypeValidation {
   }
 
   @Override
-  public void validate(String value, List<String> options) {
+  public void validate(String value, @Nullable List<String> options) {
     try {
       Double.parseDouble(value);
     } catch (NumberFormatException e) {
-      throw BadRequestException.ofL10n("errors.type.notFloat", value);
+      throw new BadRequestException("errors.type.notFloat", value);
     }
   }
 
index 68d93a3ffb75f9c5b080de3338016795290e6f1d..31f87e6a0de800ed97c6a4c0ca5b980dc390a11c 100644 (file)
@@ -36,7 +36,7 @@ public class IntegerTypeValidation implements TypeValidation {
   @Override
   public void validate(String value, List<String> options) {
     if (!NumberUtils.isDigits(value)) {
-      throw BadRequestException.ofL10n("errors.type.notInteger", value);
+      throw new BadRequestException("errors.type.notInteger", value);
     }
   }
 
index e435ead4a273062680f2704e80c75a02446ecddb..762f21effba82c6e01ac30d4dd466efc21c02e6b 100644 (file)
@@ -37,7 +37,7 @@ public class StringListTypeValidation implements TypeValidation {
   public void validate(String value, List<String> options) {
     if (!options.contains(value)) {
       String optionsAsString = StringUtils.join(options, ", ");
-      throw BadRequestException.ofL10n("errors.type.notInOptions", value, optionsAsString);
+      throw new BadRequestException("errors.type.notInOptions", value, optionsAsString);
     }
   }
 
index 3fa6c9916f3ac27b47501f5130ed048a86c02383..e754199be38aeb30487c30b50b9d43c06ea7ec66 100644 (file)
@@ -22,11 +22,12 @@ package org.sonar.server.util;
 
 import org.sonar.api.ServerComponent;
 
+import javax.annotation.Nullable;
 import java.util.List;
 
 public interface TypeValidation extends ServerComponent {
 
   String key();
 
-  void validate(String value, List<String> options);
+  void validate(String value, @Nullable List<String> options);
 }
index 5487d65cc7628d43016be595158cc744ddbee6d0..5f160211aeb1e543ea48b48583a0a14f7d278eed 100644 (file)
@@ -25,6 +25,7 @@ import com.google.common.collect.Iterables;
 import org.sonar.api.ServerComponent;
 import org.sonar.server.exceptions.BadRequestException;
 
+import javax.annotation.Nullable;
 import java.util.List;
 
 public class TypeValidations implements ServerComponent {
@@ -42,7 +43,7 @@ public class TypeValidations implements ServerComponent {
     }
   }
 
-  public void validate(String value, String type, List<String> options) {
+  public void validate(String value, String type, @Nullable List<String> options) {
     TypeValidation typeValidation = findByKey(type);
     typeValidation.validate(value, options);
   }
index d9fdd396afda80799586573d3c67db147cddc4c3..6d9f1f471d4df110eeb9ab4b160150d1bbf3f214 100644 (file)
@@ -34,20 +34,14 @@ public class Validation {
 
   public static void checkMandatoryParameter(String value, String paramName) {
     if (Strings.isNullOrEmpty(value)) {
-      throw BadRequestException.ofL10n(Validation.CANT_BE_EMPTY_MESSAGE, paramName);
-    }
-  }
-
-  public static void checkMandatoryParameter(Object value, String paramName) {
-    if (value == null) {
-      throw BadRequestException.ofL10n(Validation.CANT_BE_EMPTY_MESSAGE, paramName);
+      throw new BadRequestException(Validation.CANT_BE_EMPTY_MESSAGE, paramName);
     }
   }
 
   public static void checkMandatorySizeParameter(String value, String paramName, Integer size) {
     checkMandatoryParameter(value, paramName);
     if (!Strings.isNullOrEmpty(value) && value.length() > size) {
-      throw BadRequestException.ofL10n(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
+      throw new BadRequestException(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
     }
   }
 
index f308e1850538fadad6df8ad8bb099b8eae70f53d..498af7da45597de6d6f0e5994954a746089eee35 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.ws;
 
-import org.elasticsearch.common.collect.Lists;
 import org.picocontainer.Startable;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
@@ -29,17 +28,16 @@ import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.internal.ValidatingRequest;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.BadRequestException.Message;
+import org.sonar.server.exceptions.Errors;
+import org.sonar.server.exceptions.Message;
 import org.sonar.server.exceptions.ServerException;
 import org.sonar.server.plugins.MimeTypes;
+import org.sonar.server.user.UserSession;
 
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletResponse;
+
 import java.io.OutputStreamWriter;
-import java.util.Collection;
 import java.util.List;
-import java.util.Locale;
 
 /**
  * @since 4.2
@@ -77,7 +75,7 @@ public class WebServiceEngine implements ServerComponent, Startable {
   }
 
   public void execute(ValidatingRequest request, ServletResponse response,
-                      String controllerPath, String actionKey) {
+    String controllerPath, String actionKey) {
     try {
       WebService.Action action = getAction(controllerPath, actionKey);
       request.setAction(action);
@@ -86,15 +84,15 @@ public class WebServiceEngine implements ServerComponent, Startable {
 
     } catch (IllegalArgumentException e) {
       // TODO replace by BadRequestException in Request#mandatoryParam()
-      sendError(400, e.getMessage(), response);
+      sendErrors(response, 400, new Errors().add(Message.of(e.getMessage())));
     } catch (BadRequestException e) {
-      sendError(e, response);
+      sendErrors(response, 400, e.errors());
     } catch (ServerException e) {
-      sendError(e.httpCode(), message(e.getMessage(), e.l10nKey(), e.l10nParams()), response);
+      sendErrors(response, e.httpCode(), new Errors().add(Message.of(e.getMessage())));
     } catch (Exception e) {
       // TODO implement Request.toString()
       LoggerFactory.getLogger(getClass()).error("Fail to process request " + request, e);
-      sendError(500, e.getMessage(), response);
+      sendErrors(response, 500, new Errors().add(Message.of(e.getMessage())));
     }
   }
 
@@ -117,32 +115,7 @@ public class WebServiceEngine implements ServerComponent, Startable {
     }
   }
 
-  private void sendError(BadRequestException e, ServletResponse response) {
-    Collection<String> messages = Lists.newArrayList();
-    String exceptionMessage = message(e.getMessage(), e.l10nKey(), e.l10nParams());
-    if (exceptionMessage != null) {
-      messages.add(exceptionMessage);
-    }
-    for (Message message : e.errors()) {
-      messages.add(message(message.text(), message.l10nKey(), message.l10nParams()));
-    }
-    sendErrors(response, e.httpCode(), messages.toArray(new String[messages.size()]));
-  }
-
-  @CheckForNull
-  private String message(@Nullable String message, @Nullable String l10nKey, Object... l10nParams) {
-    if (l10nKey != null) {
-      return i18n.message(Locale.getDefault(), l10nKey, message, l10nParams);
-    } else {
-      return message;
-    }
-  }
-
-  private void sendError(int status, @Nullable String message, ServletResponse response) {
-    sendErrors(response, status, message);
-  }
-
-  private void sendErrors(ServletResponse response, int status, String... errors) {
+  private void sendErrors(ServletResponse response, int status, Errors errors) {
     ServletResponse.ServletStream stream = response.stream();
     stream.reset();
     stream.setStatus(status);
@@ -151,11 +124,7 @@ public class WebServiceEngine implements ServerComponent, Startable {
 
     try {
       json.beginObject();
-      json.name("errors").beginArray();
-      for (String message : errors) {
-        json.beginObject().prop("msg", message).endObject();
-      }
-      json.endArray();
+      errors.writeJson(json, i18n, UserSession.get().locale());
       json.endObject();
     } finally {
       // TODO if close() fails, the runtime exception should not hide the
index f141537f4e6f449d21f66bd5df6461e330e54e59..3f2d1c6e3146b9539ad9bacc1785be10d7bf2f3c 100644 (file)
@@ -151,8 +151,8 @@ public class DebtModelOperationsTest {
     try {
       service.create("Compilation", 1);
       fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("A sub characteristic can not have a sub characteristic as parent.");
+    } catch (BadRequestException e) {
+      assertThat(e.firstError().getKey()).isEqualTo("A sub characteristic can not have a sub characteristic as parent.");
     }
   }
 
@@ -177,8 +177,8 @@ public class DebtModelOperationsTest {
       service.create("Compilation", 1);
       fail();
     } catch (BadRequestException e) {
-      assertThat(e.l10nKey()).isEqualTo("errors.is_already_used");
-      assertThat(e.l10nParams()[0]).isEqualTo("Compilation");
+      assertThat(e.firstError().getKey()).isEqualTo("errors.is_already_used");
+      assertThat(e.firstError().getParams()[0]).isEqualTo("Compilation");
     }
   }
 
@@ -327,10 +327,9 @@ public class DebtModelOperationsTest {
     try {
       service.moveDown(10);
       fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Sub characteristics can not be moved.");
+    } catch (BadRequestException e) {
+      assertThat(e.firstError().getKey()).isEqualTo("Sub characteristics can not be moved.");
     }
-
     verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
   }
 
index 56cce142570d08ba760fe5dcdb0c695893914bc7..d9247211061a86bc3e08be0b6eac724b9f74423c 100644 (file)
@@ -22,91 +22,14 @@ package org.sonar.server.exceptions;
 
 import org.junit.Test;
 
-import static com.google.common.collect.Lists.newArrayList;
 import static org.fest.assertions.Assertions.assertThat;
 
 public class BadRequestExceptionTest {
 
   @Test
   public void text_error() throws Exception {
-    BadRequestException exception = BadRequestException.of("error");
+    BadRequestException exception = new BadRequestException("error");
     assertThat(exception.getMessage()).isEqualTo("error");
   }
 
-  @Test
-  public void text_error_with_list_of_errors() throws Exception {
-    BadRequestException exception = BadRequestException.of("error", newArrayList(BadRequestException.Message.of("new error")));
-
-    assertThat(exception.errors()).hasSize(1);
-    assertThat(exception.errors().get(0).text()).isEqualTo("new error");
-  }
-
-  @Test
-  public void text_error_with_list_of_l18n_errors() throws Exception {
-    BadRequestException exception = BadRequestException.of("error", newArrayList(BadRequestException.Message.ofL10n("issue.error.123", "10")));
-
-    assertThat(exception.errors()).hasSize(1);
-    assertThat(exception.errors().get(0).l10nKey()).isEqualTo("issue.error.123");
-    assertThat(exception.errors().get(0).l10nParams()).containsOnly("10");
-  }
-
-  @Test
-  public void list_of_errors() throws Exception {
-    BadRequestException exception = BadRequestException.of(newArrayList(BadRequestException.Message.of("new error")));
-
-    assertThat(exception.errors()).hasSize(1);
-    assertThat(exception.errors().get(0).text()).isEqualTo("new error");
-  }
-
-  @Test
-  public void l10n_errors() throws Exception {
-    BadRequestException exception = BadRequestException.ofL10n("issue.error.123", "10");
-    assertThat(exception.getMessage()).isNull();
-    assertThat(exception.l10nKey()).isEqualTo("issue.error.123");
-    assertThat(exception.l10nParams()).containsOnly("10");
-  }
-
-  @Test
-  public void l10n_errors_with_list_of_errors() throws Exception {
-    BadRequestException exception = BadRequestException.ofL10n(newArrayList(BadRequestException.Message.of("new error")), "issue.error.123", "10");
-    assertThat(exception.getMessage()).isNull();
-    assertThat(exception.l10nKey()).isEqualTo("issue.error.123");
-    assertThat(exception.l10nParams()).containsOnly("10");
-    assertThat(exception.errors()).hasSize(1);
-    assertThat(exception.errors().get(0).text()).isEqualTo("new error");
-  }
-
-  @Test
-  public void test_equals_and_hashcode() throws Exception {
-    BadRequestException.Message msg = BadRequestException.Message.of("error1");
-    BadRequestException.Message sameMsg = BadRequestException.Message.of("error1");
-    BadRequestException.Message msg2 = BadRequestException.Message.of("error2");
-
-    assertThat(msg.toString()).contains("error1");
-    assertThat(msg).isEqualTo(sameMsg);
-    assertThat(msg).isEqualTo(sameMsg);
-    assertThat(msg.hashCode()).isEqualTo(msg.hashCode());
-    assertThat(msg.hashCode()).isEqualTo(sameMsg.hashCode());
-
-    assertThat(msg).isNotEqualTo(msg2);
-  }
-
-  @Test
-  public void test_equals_and_hashcode_on_l10n() throws Exception {
-    BadRequestException.Message msg = BadRequestException.Message.ofL10n("error.123", "10");
-    BadRequestException.Message sameMsg = BadRequestException.Message.ofL10n("error.123", "10");
-    BadRequestException.Message msg2 = BadRequestException.Message.ofL10n("error.123", "200");
-    BadRequestException.Message msg3 = BadRequestException.Message.ofL10n("error.50");
-
-    assertThat(msg.toString()).contains("error.123").contains("10");
-    assertThat(msg).isEqualTo(msg);
-    assertThat(msg).isEqualTo(sameMsg);
-    assertThat(msg.hashCode()).isEqualTo(msg.hashCode());
-    assertThat(msg.hashCode()).isEqualTo(sameMsg.hashCode());
-
-    assertThat(msg).isNotEqualTo(msg2);
-    assertThat(msg).isNotEqualTo(msg3);
-    assertThat(msg).isNotEqualTo("issue.error.123");
-  }
-
 }
index 75f193db7776bfccbf4f050f621b55575bc08cf2..cb780e3383dc2570de0d4fdb0ef20fdedb9ca41c 100644 (file)
@@ -27,31 +27,15 @@ import static org.fest.assertions.Assertions.assertThat;
 public class ServerExceptionTest {
 
   @Test
-  public void should_create_exception_with_status(){
+  public void should_create_exception_with_status() {
     ServerException exception = new ServerException(400);
     assertThat(exception.httpCode()).isEqualTo(400);
   }
 
   @Test
-  public void should_create_exception_with_status_and_message(){
+  public void should_create_exception_with_status_and_message() {
     ServerException exception = new ServerException(404, "Not found");
     assertThat(exception.httpCode()).isEqualTo(404);
     assertThat(exception.getMessage()).isEqualTo("Not found");
   }
-
-  @Test
-  public void should_create_exception_with_status_and_l10n_message_with_param(){
-    ServerException exception = new ServerException(404, null, "key", new String[]{"value"});
-    assertThat(exception.httpCode()).isEqualTo(404);
-    assertThat(exception.l10nKey()).isEqualTo("key");
-    assertThat(exception.l10nParams()).containsOnly("value");
-  }
-
-  @Test
-  public void should_create_exception_with_status_and_l10n_message_without_param(){
-    ServerException exception = new ServerException(404, null, "key", null);
-    assertThat(exception.httpCode()).isEqualTo(404);
-    assertThat(exception.l10nKey()).isEqualTo("key");
-    assertThat(exception.l10nParams()).isEmpty();
-  }
 }
diff --git a/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java b/sonar-server/src/test/java/org/sonar/server/exceptions/VerificationsTest.java
new file mode 100644 (file)
index 0000000..57e2df0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.exceptions;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class VerificationsTest {
+
+  @Test
+  public void check() throws Exception {
+    // no exception
+    Verifications.check(true, "my.l10n.key", "foo", "bar");
+
+    try {
+      Verifications.check(false, "my.l10n.key", "foo", "bar");
+      fail();
+    } catch (BadRequestException e) {
+      assertThat(e.firstError().getKey()).isEqualTo("my.l10n.key");
+      assertThat(e.firstError().getParams()).containsOnly("foo", "bar");
+    }
+  }
+}
index f637730d0ecca5612cf7636cec6a4df2c3ce3e89..508890be52b229bd008f53de48126337548ed1e8 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.resource.ResourceDto;
 import org.sonar.core.resource.ResourceQuery;
 import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.Message;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.issue.filter.IssueFilterService;
 import org.sonar.server.user.UserSession;
@@ -653,8 +654,9 @@ public class InternalRubyIssueServiceTest {
 
   private void checkBadRequestException(Exception e, String key, Object... params) {
     BadRequestException exception = (BadRequestException) e;
-    assertThat(exception.l10nKey()).isEqualTo(key);
-    assertThat(exception.l10nParams()).containsOnly(params);
+    Message msg = exception.errors().messages().get(0);
+    assertThat(msg.getKey()).isEqualTo(key);
+    assertThat(msg.getParams()).containsOnly(params);
   }
 
   private String createLongString(int size) {
index 508c95849150636b6c44f8123a09afe3a7cdba76..990384443e69037b37b72fc07c718fa462589855 100644 (file)
@@ -155,8 +155,8 @@ public class IssueBulkChangeQueryTest {
 
   private void checkBadRequestException(Exception e, String key, Object... params) {
     BadRequestException exception = (BadRequestException) e;
-    assertThat(exception.l10nKey()).isEqualTo(key);
-    assertThat(exception.l10nParams()).containsOnly(params);
+    assertThat(exception.firstError().getKey()).isEqualTo(key);
+    assertThat(exception.firstError().getParams()).containsOnly(params);
   }
 
 }
index 78adc0d479edabdce33a241936f73fc2ba5c25b4..ad089547b51a8c889a095c4ed48fd08d6cd0a488 100644 (file)
@@ -208,7 +208,7 @@ public class QGatesWsTest {
   @Test(expected = BadRequestException.class)
   public void create_with_duplicate_name() throws Exception {
     String name = "New QG";
-    when(qGates.create(name)).thenThrow(BadRequestException.of("Name is already used"));
+    when(qGates.create(name)).thenThrow(new BadRequestException("Name is already used"));
     tester.newGetRequest("api/qualitygates", "create").setParam("name", name).execute();
   }
 
index f780b3e46343086c80deb7054f6dc33e797f1831..50584694df2dbde2385a51d2e8f229c226352e16 100644 (file)
@@ -20,7 +20,6 @@
 
 package org.sonar.server.qualityprofile;
 
-import com.google.common.collect.Multimap;
 import org.apache.ibatis.session.SqlSession;
 import org.junit.Before;
 import org.junit.Test;
@@ -54,9 +53,12 @@ import static com.google.common.collect.Lists.newArrayList;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.fest.assertions.Fail.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyListOf;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class QProfileRepositoryExporterTest {
@@ -256,7 +258,7 @@ public class QProfileRepositoryExporterTest {
       operations.exportToXml(new QProfile().setId(1), "pmd");
       fail();
     } catch (Exception e) {
-      assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("This profile does not exists.");
+      assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("This profile does not exist");
     }
 
     verify(exporter, never()).exportProfile(any(RulesProfile.class), any(Writer.class));
index 0fcdf7c3930504e8e90be64ac9c75309c82bb4cd..31c2ecb28dacc298e7a310ca437c946fa7cec6ca 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.core.rule.RuleDto;
 import org.sonar.core.rule.RuleParamDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.Message;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.rule.index.RuleIndex;
@@ -320,7 +321,8 @@ public class RuleActivatorMediumTest {
       ruleActivator.activate(activation);
       fail();
     } catch (BadRequestException e) {
-      assertThat(e.l10nKey()).isEqualTo("errors.type.notInteger");
+      Message msg = e.errors().messages().get(0);
+      assertThat(msg.getKey()).isEqualTo("errors.type.notInteger");
       verifyZeroActiveRules(XOO_PROFILE_KEY);
     }
   }
index b6756eddd4ad997ed265bbc01af895903b1fcac4..cf660c3657234146444be3797165e5cd9ed3de36 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.i18n.I18n;
 import org.sonar.server.qualityprofile.QProfileService;
 import org.sonar.server.rule.RuleService;
 import org.sonar.server.ws.WsTester;
@@ -37,6 +38,9 @@ public class QProfileRestoreBuiltInActionTest {
   @Mock
   QProfileService profileService;
 
+  @Mock
+  I18n i18n;
+
   WsTester tester;
 
   @Before
@@ -46,7 +50,7 @@ public class QProfileRestoreBuiltInActionTest {
     tester = new WsTester(new QProfilesWs(
       new QProfileRestoreBuiltInAction(this.profileService),
       new RuleActivationActions(profileService),
-      new BulkRuleActivationActions(profileService, ruleService)));
+      new BulkRuleActivationActions(profileService, ruleService, i18n)));
   }
 
   @Test
@@ -56,29 +60,4 @@ public class QProfileRestoreBuiltInActionTest {
     WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "restore_built_in").setParam("language", "java");
     request.execute().assertNoContent();
   }
-
-  // TODO
-//  @Test
-//  public void show_infos() throws Exception {
-//    when(profileService.recreateBuiltInProfilesByLanguage("java")).thenReturn(new QProfileResult().addInfos(newArrayList("Some info")));
-//
-//    WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "recreate_built_in").setParam("language", "java");
-//    request.execute().assertJson(getClass(), "show_infos.json");
-//  }
-//
-//  @Test
-//  public void show_warnings() throws Exception {
-//    when(profileService.recreateBuiltInProfilesByLanguage("java")).thenReturn(new QProfileResult().addWarnings(newArrayList("Some warning")));
-//
-//    WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "recreate_built_in").setParam("language", "java");
-//    request.execute().assertJson(getClass(), "show_warnings.json");
-//  }
-//
-//  @Test
-//  public void show_infos_and_warnings() throws Exception {
-//    when(profileService.recreateBuiltInProfilesByLanguage("java")).thenReturn(new QProfileResult().addInfos(newArrayList("Some info")).addWarnings(newArrayList("Some warning")));
-//
-//    WsTester.TestRequest request = tester.newPostRequest("api/qualityprofiles", "recreate_built_in").setParam("language", "java");
-//    request.execute().assertJson(getClass(), "show_infos_and_warnings.json");
-//  }
 }
index a26a4f92cd8f9bbd3c264b6b0b68bab725b06b9a..e54509a3de76970c370958843db7f1d406f70bb0 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile.ws;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.i18n.I18n;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.server.qualityprofile.QProfileService;
 import org.sonar.server.rule.RuleService;
@@ -38,10 +39,11 @@ public class QProfilesWsTest {
   public void setUp() {
     QProfileService profileService = mock(QProfileService.class);
     RuleService ruleService = mock(RuleService.class);
+    I18n i18n = mock(I18n.class);
     controller = new WsTester(new QProfilesWs(new QProfileRestoreBuiltInAction(
       mock(QProfileService.class)),
       new RuleActivationActions(profileService),
-      new BulkRuleActivationActions(profileService, ruleService)
+      new BulkRuleActivationActions(profileService, ruleService, i18n)
     )).controller(QProfilesWs.API_ENDPOINT);
   }
 
index 8c07873d21de6c9840079b6267548312f388476e..031a1e984683f4c4d91bd112d5f73f38f76ac095 100644 (file)
@@ -57,7 +57,7 @@ public class BooleanTypeValidationTest {
     } catch (Exception e) {
       assertThat(e).isInstanceOf(BadRequestException.class);
       BadRequestException badRequestException = (BadRequestException) e;
-      assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
+      assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
     }
   }
 
index a1a11664b0ff0ade829c05ed66adcbf52ed14028..7c7b170475f146d4b54af74ddf30cdb79551e071 100644 (file)
@@ -55,7 +55,7 @@ public class FloatTypeValidationTest {
     } catch (Exception e) {
       assertThat(e).isInstanceOf(BadRequestException.class);
       BadRequestException badRequestException = (BadRequestException) e;
-      assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
+      assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
     }
   }
 
index 9db9ed73e23abf6ccfc86a009688f8470e81d0db..43620979026aaa243e618ed5b1162462b41e3a5e 100644 (file)
@@ -54,7 +54,7 @@ public class IntegerTypeValidationTest {
     } catch (Exception e) {
       assertThat(e).isInstanceOf(BadRequestException.class);
       BadRequestException badRequestException = (BadRequestException) e;
-      assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
+      assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
     }
   }
 
index 0c50e23d9b9f70f35e2cf5f42470c9ff4b352264..750d91ef7f1c9201fa13e789dcb11bcd10e94385 100644 (file)
@@ -55,8 +55,8 @@ public class StringListTypeValidationTest {
     } catch (Exception e) {
       assertThat(e).isInstanceOf(BadRequestException.class);
       BadRequestException badRequestException = (BadRequestException) e;
-      assertThat(badRequestException.l10nParams()[0]).isEqualTo("abc");
-      assertThat(badRequestException.l10nParams()[1]).isEqualTo("a, b, c");
+      assertThat(badRequestException.firstError().getParams()[0]).isEqualTo("abc");
+      assertThat(badRequestException.firstError().getParams()[1]).isEqualTo("a, b, c");
     }
   }
 
index 604b55400333184f4c2f2de644e5d75500be0eb5..fc2331d5f862f43656447f3388e8644b387e9461 100644 (file)
@@ -64,7 +64,7 @@ public class TypeValidationsTest {
     } catch (Exception e) {
       assertThat(e).isInstanceOf(BadRequestException.class);
       BadRequestException badRequestException = (BadRequestException) e;
-      assertThat(badRequestException.getMessage()).isEqualTo("Type 'Unknown' is not valid.");
+      assertThat(badRequestException.firstError().getKey()).isEqualTo("Type 'Unknown' is not valid.");
     }
   }
 
index 6bf8690856d43cb5de85108a81404d5fd361e5c9..738f763865c7988050286e421590290e73f03869 100644 (file)
  */
 package org.sonar.server.ws;
 
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
@@ -32,17 +33,19 @@ import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.internal.ValidatingRequest;
 import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.BadRequestException.Message;
-import org.sonar.server.exceptions.ServerException;
+import org.sonar.server.exceptions.Errors;
+import org.sonar.server.exceptions.Message;
 import org.sonar.server.plugins.MimeTypes;
 
 import javax.annotation.Nullable;
+
 import java.io.IOException;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
 import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -83,7 +86,7 @@ public class WebServiceEngineTest {
   }
 
   I18n i18n = mock(I18n.class);
-  WebServiceEngine engine = new WebServiceEngine(new WebService[]{new SystemWebService()}, i18n);
+  WebServiceEngine engine = new WebServiceEngine(new WebService[] {new SystemWebService()}, i18n);
 
   @Before
   public void start() {
@@ -230,13 +233,13 @@ public class WebServiceEngineTest {
   public void bad_request_with_i18n_message() throws Exception {
     ValidatingRequest request = new SimpleRequest("GET").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");
+    when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("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().outputAsString()).isEqualTo(
+      "{\"errors\":[{\"msg\":\"reason #0\"}]}"
+    );
     assertThat(response.stream().httpStatus()).isEqualTo(400);
     assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
   }
@@ -261,34 +264,20 @@ public class WebServiceEngineTest {
   public void bad_request_with_multiple_i18n_messages() throws Exception {
     ValidatingRequest request = new SimpleRequest("GET").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");
+    when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("reason #0");
+    when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 1)).thenReturn("reason #1");
+    when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 2)).thenReturn("reason #2");
 
     engine.execute(request, response, "api/system", "fail_with_multiple_i18n_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().outputAsString()).isEqualTo("{\"errors\":[" +
+      "{\"msg\":\"reason #0\"}," +
+      "{\"msg\":\"reason #1\"}," +
+      "{\"msg\":\"reason #2\"}]}");
     assertThat(response.stream().httpStatus()).isEqualTo(400);
     assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
   }
 
-  @Test
-  public void server_exception_with_i18n_message() throws Exception {
-    ValidatingRequest request = new SimpleRequest("GET");
-    ServletResponse response = new ServletResponse();
-    when(i18n.message(eq(Locale.getDefault()), eq("not.found"), anyString())).thenReturn("Element is not found");
-
-    engine.execute(request, response, "api/system", "server_exception_with_i18n_message");
-
-    assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Element is not found\"}]}");
-    assertThat(response.stream().httpStatus()).isEqualTo(404);
-    assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON);
-  }
-
   static class SystemWebService implements WebService {
     @Override
     public void define(Context context) {
@@ -327,7 +316,7 @@ public class WebServiceEngineTest {
         .setHandler(new RequestHandler() {
           @Override
           public void handle(Request request, Response response) {
-            throw BadRequestException.ofL10n("bad.request.reason", 0);
+            throw new BadRequestException("bad.request.reason", 0);
           }
         });
       newController.createAction("fail_with_multiple_messages")
@@ -335,11 +324,11 @@ public class WebServiceEngineTest {
         .setHandler(new RequestHandler() {
           @Override
           public void handle(Request request, Response response) {
-            List<BadRequestException.Message> errors = Lists.newArrayList();
+            Errors errors = new Errors();
             for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
               errors.add(Message.of("Bad request reason #" + count));
             }
-            throw BadRequestException.of(errors);
+            throw new BadRequestException(errors);
           }
         });
       newController.createAction("fail_with_multiple_i18n_messages")
@@ -347,18 +336,11 @@ public class WebServiceEngineTest {
         .setHandler(new RequestHandler() {
           @Override
           public void handle(Request request, Response response) {
-            List<BadRequestException.Message> errors = Lists.newArrayList();
+            Errors errors = new Errors();
             for (int count = 0; count < Integer.valueOf(request.param("count")); count++) {
-              errors.add(Message.ofL10n("bad.request.reason", count));
+              errors.add(Message.of("bad.request.reason", count));
             }
-            throw BadRequestException.of(errors);
-          }
-        });
-      newController.createAction("server_exception_with_i18n_message")
-        .setHandler(new RequestHandler() {
-          @Override
-          public void handle(Request request, Response response) {
-            throw new ServerException(404, null, "not.found", null);
+            throw new BadRequestException(errors);
           }
         });
       newController.createAction("alive")