]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3755 refactor issue search
authorSimon Brandhof <simon.brandhof@gmail.com>
Fri, 3 May 2013 16:58:14 +0000 (18:58 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Fri, 3 May 2013 16:58:14 +0000 (18:58 +0200)
26 files changed:
sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueFinder.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQuery.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/JRubyIssues.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/Paging.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/WebIssues.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/utils/Paging.java [new file with mode: 0644]
sonar-plugin-api/src/test/java/org/sonar/api/issue/PagingTest.java [deleted file]
sonar-plugin-api/src/test/java/org/sonar/api/utils/PagingTest.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/issue/JRubyApiIssues.java [deleted file]
sonar-server/src/main/java/org/sonar/server/issue/JRubyInternalIssues.java
sonar-server/src/main/java/org/sonar/server/issue/ServerIssueFinder.java
sonar-server/src/main/java/org/sonar/server/issue/WebIssuesApi.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/platform/Platform.java
sonar-server/src/main/java/org/sonar/server/rule/JRubyRules.java [deleted file]
sonar-server/src/main/java/org/sonar/server/rule/WebRules.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/text/JRubyText.java [deleted file]
sonar-server/src/main/java/org/sonar/server/text/WebText.java [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/issues_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb
sonar-server/src/test/java/org/sonar/server/issue/JRubyApiIssuesTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/issue/ServerIssueFinderTest.java
sonar-server/src/test/java/org/sonar/server/issue/WebIssuesApiTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/rule/JRubyRulesTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/rule/WebRulesTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/text/JRubyTextTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/text/WebTextTest.java [new file with mode: 0644]

index 7ba13797017ec94ba4f3498870814ec3088ab622..735225e461e4b27d8f89207e0700225f0ae41805 100644 (file)
@@ -23,10 +23,10 @@ package org.sonar.api.issue;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.component.Component;
 import org.sonar.api.rules.Rule;
+import org.sonar.api.utils.Paging;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-
 import java.util.Collection;
 import java.util.List;
 
@@ -62,10 +62,4 @@ public interface IssueFinder extends ServerComponent {
 
   @CheckForNull
   Issue findByKey(String key /* TODO @Nullable Integer currentUserId */);
-
-  /*
-  Map<RuleKey, Rule> rules(Collection<Issue> issues);
-
-  Map<String, Component> components(Collection<Issue> issues);
-*/
 }
index 796a6d42df7403416e8641ccef2f9d2422a84258..d3fedd09ac7de6e0bae9bc6ec6a3533ba0a02954 100644 (file)
@@ -157,7 +157,7 @@ public class IssueQuery {
   public static class Builder {
 
     private enum Sort {
-      created, updated, closed, assignee;
+      created, updated, closed, assignee
     }
 
     private static final int DEFAULT_PAGE_SIZE = 100;
@@ -265,15 +265,15 @@ public class IssueQuery {
     }
 
     public Builder pageSize(@Nullable Integer i) {
-      Preconditions.checkArgument(i == null || i.intValue() > 0, "Page size must be greater than 0 (got " + i + ")");
-      Preconditions.checkArgument(i == null || i.intValue() < MAX_PAGE_SIZE, "Page size must be less than " + MAX_PAGE_SIZE + " (got " + i + ")");
+      Preconditions.checkArgument(i == null || i > 0, "Page size must be greater than 0 (got " + i + ")");
+      Preconditions.checkArgument(i == null || i < MAX_PAGE_SIZE, "Page size must be less than " + MAX_PAGE_SIZE + " (got " + i + ")");
       this.pageSize = (i == null ? DEFAULT_PAGE_SIZE : i.intValue());
       return this;
     }
 
     public Builder pageIndex(@Nullable Integer i) {
-      Preconditions.checkArgument(i == null || i.intValue() > 0, "Page index must be greater than 0 (got " + i + ")");
-      this.pageIndex = (i == null ? DEFAULT_PAGE_INDEX : i.intValue());
+      Preconditions.checkArgument(i == null || i > 0, "Page index must be greater than 0 (got " + i + ")");
+      this.pageIndex = (i == null ? DEFAULT_PAGE_INDEX : i);
       return this;
     }
 
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/JRubyIssues.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/JRubyIssues.java
deleted file mode 100644 (file)
index a56d443..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.api.issue;
-
-import org.sonar.api.ServerComponent;
-
-import java.util.Map;
-
-/**
- * Facade for JRuby on Rails extensions to request issues.
- * <p>
- * Reference from Ruby code : <code>Api.issues</code>
- * </p>
- *
- * @since 3.6
- */
-public interface JRubyIssues extends ServerComponent {
-
-  /**
-   * Search for issues.
-   * <p/>
-   * Ruby: <code>Api.issues.find(hash_of_parameters)</code>
-   * <p/>
-   * <ul>
-   * TODO document parameters
-   * </ul>
-   */
-  IssueFinder.Results find(Map<String, Object> parameters);
-
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Paging.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Paging.java
deleted file mode 100644 (file)
index 867cec8..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.api.issue;
-
-/**
- * TODO move outside this package
- * @since 3.6
- */
-public class Paging {
-
-  private final int pageSize;
-  private final int pageIndex;
-  private final int total;
-
-  public Paging(int pageSize, int pageIndex, int total) {
-    this.pageSize = pageSize;
-    this.pageIndex = pageIndex;
-    this.total = total;
-  }
-
-  public int pageIndex() {
-    return pageIndex;
-  }
-
-  public int pageSize() {
-    return pageSize;
-  }
-
-  public int total() {
-    return total;
-  }
-
-  public int offset(){
-    return (pageIndex - 1) * pageSize;
-  }
-
-  public int pages() {
-    int p = (total / pageSize);
-    if ((total % pageSize) > 0) {
-      p++;
-    }
-    return p;
-  }
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/WebIssues.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/WebIssues.java
new file mode 100644 (file)
index 0000000..67932f0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.api.issue;
+
+import org.sonar.api.ServerComponent;
+
+import java.util.Map;
+
+/**
+ * Facade for JRuby on Rails extensions to request issues.
+ * <p>
+ * Reference from Ruby code : <code>Api.issues</code>
+ * </p>
+ *
+ * @since 3.6
+ */
+public interface WebIssues extends ServerComponent {
+
+  /**
+   * Search for issues.
+   * <p/>
+   * Ruby: <code>Api.issues.find(hash_of_parameters)</code>
+   * <p/>
+   * <ul>
+   * TODO document parameters
+   * </ul>
+   */
+  IssueFinder.Results find(Map<String, Object> parameters);
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Paging.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Paging.java
new file mode 100644 (file)
index 0000000..0fc31c4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.api.utils;
+
+/**
+ * @since 3.6
+ */
+public class Paging {
+
+  private final int pageSize;
+  private final int pageIndex;
+  private final int total;
+
+  private Paging(int pageSize, int pageIndex, int total) {
+    this.pageSize = pageSize;
+    this.pageIndex = pageIndex;
+    this.total = total;
+  }
+
+  /**
+   * Page index, starting with 1.
+   */
+  public int pageIndex() {
+    return pageIndex;
+  }
+
+  /**
+   * Maximum number of items per page. It is greater than 0.
+   */
+  public int pageSize() {
+    return pageSize;
+  }
+
+  /**
+   * Total number of items. It is greater than or equal 0.
+   */
+  public int total() {
+    return total;
+  }
+
+  public int offset(){
+    return (pageIndex - 1) * pageSize;
+  }
+
+  /**
+   * Number of pages. It is greater than or equal 0.
+   */
+  public int pages() {
+    int p = (total / pageSize);
+    if ((total % pageSize) > 0) {
+      p++;
+    }
+    return p;
+  }
+
+  public static Paging create(int pageSize, int pageIndex, int totalItems) {
+    if (pageSize<1) {
+      throw new IllegalArgumentException("Page size must be strictly positive. Got " + pageSize);
+    }
+    if (pageIndex<1) {
+      throw new IllegalArgumentException("Page index must be strictly positive. Got " + pageIndex);
+    }
+    if (totalItems<0) {
+      throw new IllegalArgumentException("Total items must be positive. Got " + totalItems);
+    }
+    return new Paging(pageSize, pageIndex, totalItems);
+  }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/issue/PagingTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/issue/PagingTest.java
deleted file mode 100644 (file)
index ca9dbf2..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.api.issue;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class PagingTest {
-
-  @Test
-  public void test_pagination(){
-    Paging paging = new Paging(5, 1, 20);
-
-    assertThat(paging.pageSize()).isEqualTo(5);
-    assertThat(paging.pageIndex()).isEqualTo(1);
-    assertThat(paging.total()).isEqualTo(20);
-
-    assertThat(paging.offset()).isEqualTo(0);
-    assertThat(paging.pages()).isEqualTo(4);
-  }
-
-  @Test
-  public void test_offset(){
-    assertThat(new Paging(5, 1, 20).offset()).isEqualTo(0);
-    assertThat(new Paging(5, 2, 20).offset()).isEqualTo(5);
-  }
-
-  @Test
-  public void test_number_of_pages(){
-    assertThat(new Paging(5, 2, 20).pages()).isEqualTo(4);
-    assertThat(new Paging(5, 2, 21).pages()).isEqualTo(5);
-    assertThat(new Paging(5, 2, 25).pages()).isEqualTo(5);
-    assertThat(new Paging(5, 2, 26).pages()).isEqualTo(6);
-  }
-}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/PagingTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/PagingTest.java
new file mode 100644 (file)
index 0000000..0d28a7b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.api.utils;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class PagingTest {
+
+  @Test
+  public void test_pagination() {
+    Paging paging = Paging.create(5, 1, 20);
+
+    assertThat(paging.pageSize()).isEqualTo(5);
+    assertThat(paging.pageIndex()).isEqualTo(1);
+    assertThat(paging.total()).isEqualTo(20);
+
+    assertThat(paging.offset()).isEqualTo(0);
+    assertThat(paging.pages()).isEqualTo(4);
+  }
+
+  @Test
+  public void test_offset() {
+    assertThat(Paging.create(5, 1, 20).offset()).isEqualTo(0);
+    assertThat(Paging.create(5, 2, 20).offset()).isEqualTo(5);
+  }
+
+  @Test
+  public void test_number_of_pages() {
+    assertThat(Paging.create(5, 2, 20).pages()).isEqualTo(4);
+    assertThat(Paging.create(5, 2, 21).pages()).isEqualTo(5);
+    assertThat(Paging.create(5, 2, 25).pages()).isEqualTo(5);
+    assertThat(Paging.create(5, 2, 26).pages()).isEqualTo(6);
+  }
+
+  @Test
+  public void page_size_should_be_strictly_positive() throws Exception {
+    try {
+      Paging.create(0, 5, 5);
+      fail();
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("Page size must be strictly positive. Got 0");
+    }
+  }
+
+  @Test
+  public void page_index_should_be_strictly_positive() throws Exception {
+    try {
+      Paging.create(5, 0, 5);
+      fail();
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("Page index must be strictly positive. Got 0");
+    }
+  }
+
+  @Test
+  public void total_items_should_be_positive() throws Exception {
+    try {
+      Paging.create(5, 5, -1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("Total items must be positive. Got -1");
+    }
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/JRubyApiIssues.java b/sonar-server/src/main/java/org/sonar/server/issue/JRubyApiIssues.java
deleted file mode 100644 (file)
index c1170d2..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.issue;
-
-import com.google.common.base.Function;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
-import com.google.common.primitives.Ints;
-import org.sonar.api.issue.IssueFinder;
-import org.sonar.api.issue.IssueQuery;
-import org.sonar.api.issue.JRubyIssues;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.web.UserRole;
-import org.sonar.server.platform.UserSession;
-
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Facade of issue components for JRuby on Rails webapp
- *
- * @since 3.6
- */
-public class JRubyApiIssues implements JRubyIssues {
-
-  private final IssueFinder finder;
-
-  public JRubyApiIssues(IssueFinder f) {
-    this.finder = f;
-  }
-
-  /**
-   * Requires the role {@link org.sonar.api.web.UserRole#CODEVIEWER}
-   */
-  @Override
-  public IssueFinder.Results find(Map<String, Object> params) {
-    // TODO move the role to IssueFinder
-    return finder.find(toQuery(params), UserSession.get().userId(), UserRole.CODEVIEWER);
-  }
-
-  IssueQuery toQuery(Map<String, Object> props) {
-    IssueQuery.Builder builder = IssueQuery.builder();
-    builder.issueKeys(toStrings(props.get("issueKeys")));
-    builder.severities(toStrings(props.get("severities")));
-    builder.statuses(toStrings(props.get("statuses")));
-    builder.resolutions(toStrings(props.get("resolutions")));
-    builder.components(toStrings(props.get("components")));
-    builder.componentRoots(toStrings(props.get("componentRoots")));
-    builder.rules(toRules(props.get("rules")));
-    builder.userLogins(toStrings(props.get("userLogins")));
-    builder.assignees(toStrings(props.get("assignees")));
-    builder.assigned(toBoolean(props.get("assigned")));
-    builder.createdAfter(toDate(props.get("createdAfter")));
-    builder.createdBefore(toDate(props.get("createdBefore")));
-    builder.pageSize(toInteger(props.get("pageSize")));
-    builder.pageIndex(toInteger(props.get("pageIndex")));
-    return builder.build();
-  }
-
-  @SuppressWarnings("unchecked")
-  static Collection<RuleKey> toRules(Object o) {
-    Collection<RuleKey> result = null;
-    if (o != null) {
-      if (o instanceof List) {
-        // assume that it contains only strings
-        result = stringsToRules((List<String>) o);
-      } else if (o instanceof String) {
-        result = stringsToRules(Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((String) o)));
-      }
-    }
-    return result;
-  }
-
-  private static Collection<RuleKey> stringsToRules(Collection<String> o) {
-    return Collections2.transform(o, new Function<String, RuleKey>() {
-      @Override
-      public RuleKey apply(@Nullable String s) {
-        return s != null ? RuleKey.parse(s) : null;
-      }
-    });
-  }
-
-  static List<String> toStrings(Object o) {
-    List<String> result = null;
-    if (o != null) {
-      if (o instanceof List) {
-        // assume that it contains only strings
-        result = (List) o;
-      } else if (o instanceof CharSequence) {
-        result = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) o));
-      }
-    }
-    return result;
-  }
-
-  Integer toInteger(Object o) {
-    if (o instanceof Integer) {
-      return (Integer) o;
-    }
-    if (o instanceof Long) {
-      return Ints.checkedCast((Long) o);
-    }
-
-    if (o instanceof String) {
-      return Integer.parseInt((String) o);
-    }
-    return null;
-  }
-
-  Double toDouble(Object o) {
-    if (o instanceof Double) {
-      return (Double) o;
-    }
-    if (o instanceof String) {
-      return Double.parseDouble((String) o);
-    }
-    return null;
-  }
-
-
-  Date toDate(Object o) {
-    if (o instanceof Date) {
-      return (Date) o;
-    }
-    if (o instanceof String) {
-      return DateUtils.parseDateTime((String) o);
-    }
-    return null;
-  }
-
-  Boolean toBoolean(Object o) {
-    if (o instanceof Boolean) {
-      return (Boolean) o;
-    }
-    if (o instanceof String) {
-      return Boolean.parseBoolean((String) o);
-    }
-    return null;
-  }
-
-  public void start() {
-    // used to force pico to instantiate the singleton at startup
-  }
-}
index 2dc008f801f556d350eec559cd8ab41ddf498afc..780c4986ff0187ebbe040048d7cc1d99267aadd9 100644 (file)
@@ -33,7 +33,8 @@ import java.util.List;
 import java.util.Map;
 
 /**
- * All the issue features that are not published to public API
+ * All the issue features that are not published to public API.
+ * TODO to be renamed to WebIssuesInternal
  */
 public class JRubyInternalIssues implements ServerComponent {
 
index 01402ad421754dece7a059592d6c9e8b32579d4d..36d0985bc220fbfc6e517fc3e47863c640846441 100644 (file)
 package org.sonar.server.issue;
 
 import com.google.common.base.Predicate;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Sets;
+import com.google.common.collect.*;
 import org.apache.ibatis.session.SqlSession;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.component.Component;
-import org.sonar.api.issue.*;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueFinder;
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
+import org.sonar.api.utils.Paging;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.db.ActionPlanIssueDao;
 import org.sonar.core.issue.db.ActionPlanIssueDto;
@@ -41,7 +43,6 @@ import org.sonar.core.rule.DefaultRuleFinder;
 import org.sonar.core.user.AuthorizationDao;
 
 import javax.annotation.Nullable;
-
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -77,14 +78,14 @@ public class ServerIssueFinder implements IssueFinder {
     SqlSession sqlSession = myBatis.openSession();
     try {
       List<IssueDto> allIssuesDto = issueDao.selectIssueIdsAndComponentsId(query, sqlSession);
-      Set<Integer> componentIds = getResourceIds(allIssuesDto);
+      Set<Integer> componentIds = extractResourceIds(allIssuesDto);
       Set<Integer> authorizedComponentIds = authorizationDao.keepAuthorizedComponentIds(componentIds, currentUserId, role, sqlSession);
-      List<IssueDto> authorizedIssues = getAuthorizedIssues(allIssuesDto, authorizedComponentIds);
-      Paging paging = new Paging(query.pageSize(), query.pageIndex(), authorizedIssues.size());
-      Set<Long> paginatedAuthorizedIssueIds = getPaginatedAuthorizedIssueIds(authorizedIssues, paging);
+      List<IssueDto> authorizedIssues = authorized(allIssuesDto, authorizedComponentIds);
+      Paging paging = Paging.create(query.pageSize(), query.pageIndex(), authorizedIssues.size());
+      Set<Long> pagedAuthorizedIssueIds = pagedAuthorizedIssueIds(authorizedIssues, paging);
 
-      Collection<IssueDto> dtos = issueDao.selectByIds(paginatedAuthorizedIssueIds, sqlSession);
-      Set<Integer> ruleIds = Sets.newLinkedHashSet();
+      Collection<IssueDto> dtos = issueDao.selectByIds(pagedAuthorizedIssueIds, sqlSession);
+      Set<Integer> ruleIds = Sets.newHashSet();
       List<Issue> issues = newArrayList();
       List<Long> issueIds = newArrayList();
       Map<Long, Issue> issuesById = newHashMap();
@@ -102,23 +103,26 @@ public class ServerIssueFinder implements IssueFinder {
       ListMultimap<Issue, ActionPlan> actionPlansByIssueKey = createActionPlansByIssue(actionPlanIssueDtos, issuesById);
       setActionPlans(issues, actionPlansByIssueKey);
 
-      return new DefaultResults(issues, getRulesByIssue(issues, ruleIds), getComponentsByIssue(issues, componentIds), actionPlansByIssueKey,
+      return new DefaultResults(issues,
+        findRules(ruleIds),
+        findComponents(componentIds),
+        actionPlansByIssueKey,
         paging, authorizedIssues.size() != allIssuesDto.size());
     } finally {
       MyBatis.closeQuietly(sqlSession);
     }
   }
 
-  private Set<Integer> getResourceIds(List<IssueDto> allIssuesDto) {
+  private Set<Integer> extractResourceIds(List<IssueDto> dtos) {
     Set<Integer> componentIds = Sets.newLinkedHashSet();
-    for (IssueDto issueDto : allIssuesDto) {
+    for (IssueDto issueDto : dtos) {
       componentIds.add(issueDto.getResourceId());
     }
     return componentIds;
   }
 
-  private List<IssueDto> getAuthorizedIssues(List<IssueDto> allIssuesDto, final Set<Integer> authorizedComponentIds) {
-    return newArrayList(Iterables.filter(allIssuesDto, new Predicate<IssueDto>() {
+  private List<IssueDto> authorized(List<IssueDto> dtos, final Set<Integer> authorizedComponentIds) {
+    return newArrayList(Iterables.filter(dtos, new Predicate<IssueDto>() {
       @Override
       public boolean apply(IssueDto issueDto) {
         return authorizedComponentIds.contains(issueDto.getResourceId());
@@ -126,7 +130,7 @@ public class ServerIssueFinder implements IssueFinder {
     }));
   }
 
-  private Set<Long> getPaginatedAuthorizedIssueIds(List<IssueDto> authorizedIssues, Paging paging) {
+  private Set<Long> pagedAuthorizedIssueIds(List<IssueDto> authorizedIssues, Paging paging) {
     Set<Long> issueIds = Sets.newLinkedHashSet();
     int index = 0;
     for (IssueDto issueDto : authorizedIssues) {
@@ -140,40 +144,12 @@ public class ServerIssueFinder implements IssueFinder {
     return issueIds;
   }
 
-  private Map<Issue, Rule> getRulesByIssue(List<Issue> issues, Set<Integer> ruleIds) {
-    Map<Issue, Rule> rulesByIssue = newHashMap();
-    Collection<Rule> rules = ruleFinder.findByIds(ruleIds);
-    for (Issue issue : issues) {
-      rulesByIssue.put(issue, findRule(issue, rules));
-    }
-    return rulesByIssue;
+  private Collection<Rule> findRules(Set<Integer> ruleIds) {
+    return ruleFinder.findByIds(ruleIds);
   }
 
-  private Rule findRule(final Issue issue, Collection<Rule> rules) {
-    return Iterables.find(rules, new Predicate<Rule>() {
-      @Override
-      public boolean apply(Rule rule) {
-        return issue.ruleKey().equals(rule.ruleKey());
-      }
-    }, null);
-  }
-
-  private Map<Issue, Component> getComponentsByIssue(List<Issue> issues, Set<Integer> componentIds) {
-    Map<Issue, Component> componentsByIssue = newHashMap();
-    Collection<Component> components = resourceDao.findByIds(componentIds);
-    for (Issue issue : issues) {
-      componentsByIssue.put(issue, findComponent(issue, components));
-    }
-    return componentsByIssue;
-  }
-
-  private Component findComponent(final Issue issue, Collection<Component> components) {
-    return Iterables.find(components, new Predicate<Component>() {
-      @Override
-      public boolean apply(Component component) {
-        return issue.componentKey().equals(component.key());
-      }
-    }, null);
+  private Collection<Component> findComponents(Set<Integer> componentIds) {
+    return resourceDao.findByIds(componentIds);
   }
 
   private ListMultimap createActionPlansByIssue(Collection<ActionPlanIssueDto> actionPlanIssueDtos, Map<Long, Issue> issuesById) {
@@ -185,7 +161,7 @@ public class ServerIssueFinder implements IssueFinder {
     return actionPlansByIssue;
   }
 
-  private void setActionPlans(List<Issue> issues, ListMultimap<Issue, ActionPlan> actionPlansByIssueKey){
+  private void setActionPlans(List<Issue> issues, ListMultimap<Issue, ActionPlan> actionPlansByIssueKey) {
     for (Issue issue : issues) {
       DefaultIssue defaultIssue = (DefaultIssue) issue;
       List<ActionPlan> actionPlans = actionPlansByIssueKey.get(issue);
@@ -200,17 +176,25 @@ public class ServerIssueFinder implements IssueFinder {
 
   static class DefaultResults implements Results {
     private final List<Issue> issues;
-    private final Paging paging;
-    private final Map<Issue, Rule> rulesByIssue;
-    private final Map<Issue, Component> componentsByIssue;
+    private final Map<RuleKey, Rule> rulesByKey = Maps.newHashMap();
+    private final Map<String, Component> componentsByKey = Maps.newHashMap();
     private final ListMultimap<Issue, ActionPlan> actionPlansByIssue;
     private final boolean securityExclusions;
+    private final Paging paging;
 
-    DefaultResults(List<Issue> issues, Map<Issue, Rule> rulesByIssue, Map<Issue, Component> componentsByIssue, ListMultimap<Issue, ActionPlan> actionPlansByIssue,
+    DefaultResults(List<Issue> issues,
+                   Collection<Rule> rules,
+                   Collection<Component> components,
+                   ListMultimap<Issue,
+                     ActionPlan> actionPlansByIssue,
                    Paging paging, boolean securityExclusions) {
       this.issues = issues;
-      this.rulesByIssue = rulesByIssue;
-      this.componentsByIssue = componentsByIssue;
+      for (Rule rule : rules) {
+        rulesByKey.put(rule.ruleKey(), rule);
+      }
+      for (Component component : components) {
+        componentsByKey.put(component.key(), component);
+      }
       this.actionPlansByIssue = actionPlansByIssue;
       this.paging = paging;
       this.securityExclusions = securityExclusions;
@@ -222,19 +206,19 @@ public class ServerIssueFinder implements IssueFinder {
     }
 
     public Rule rule(Issue issue) {
-      return rulesByIssue.get(issue);
+      return rulesByKey.get(issue.ruleKey());
     }
 
     public Collection<Rule> rules() {
-      return rulesByIssue.values();
+      return rulesByKey.values();
     }
 
     public Component component(Issue issue) {
-      return componentsByIssue.get(issue);
+      return componentsByKey.get(issue.componentKey());
     }
 
     public Collection<Component> components() {
-      return componentsByIssue.values();
+      return componentsByKey.values();
     }
 
     public Collection<ActionPlan> actionPlans(Issue issue) {
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesApi.java b/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesApi.java
new file mode 100644 (file)
index 0000000..35d9f60
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.issue;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.primitives.Ints;
+import org.sonar.api.issue.IssueFinder;
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.issue.WebIssues;
+import org.sonar.api.issue.WebIssues;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.web.UserRole;
+import org.sonar.server.platform.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Facade of issue components for JRuby on Rails webapp
+ *
+ * @since 3.6
+ */
+public class WebIssuesApi implements WebIssues {
+
+  private final IssueFinder finder;
+
+  public WebIssuesApi(IssueFinder f) {
+    this.finder = f;
+  }
+
+  /**
+   * Requires the role {@link org.sonar.api.web.UserRole#CODEVIEWER}
+   */
+  @Override
+  public IssueFinder.Results find(Map<String, Object> params) {
+    // TODO move the role to IssueFinder
+    return finder.find(toQuery(params), UserSession.get().userId(), UserRole.CODEVIEWER);
+  }
+
+  IssueQuery toQuery(Map<String, Object> props) {
+    IssueQuery.Builder builder = IssueQuery.builder();
+    builder.issueKeys(toStrings(props.get("issueKeys")));
+    builder.severities(toStrings(props.get("severities")));
+    builder.statuses(toStrings(props.get("statuses")));
+    builder.resolutions(toStrings(props.get("resolutions")));
+    builder.components(toStrings(props.get("components")));
+    builder.componentRoots(toStrings(props.get("componentRoots")));
+    builder.rules(toRules(props.get("rules")));
+    builder.userLogins(toStrings(props.get("userLogins")));
+    builder.assignees(toStrings(props.get("assignees")));
+    builder.assigned(toBoolean(props.get("assigned")));
+    builder.createdAfter(toDate(props.get("createdAfter")));
+    builder.createdBefore(toDate(props.get("createdBefore")));
+    builder.pageSize(toInteger(props.get("pageSize")));
+    builder.pageIndex(toInteger(props.get("pageIndex")));
+    return builder.build();
+  }
+
+  @SuppressWarnings("unchecked")
+  static Collection<RuleKey> toRules(Object o) {
+    Collection<RuleKey> result = null;
+    if (o != null) {
+      if (o instanceof List) {
+        // assume that it contains only strings
+        result = stringsToRules((List<String>) o);
+      } else if (o instanceof String) {
+        result = stringsToRules(Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((String) o)));
+      }
+    }
+    return result;
+  }
+
+  private static Collection<RuleKey> stringsToRules(Collection<String> o) {
+    return Collections2.transform(o, new Function<String, RuleKey>() {
+      @Override
+      public RuleKey apply(@Nullable String s) {
+        return s != null ? RuleKey.parse(s) : null;
+      }
+    });
+  }
+
+  static List<String> toStrings(Object o) {
+    List<String> result = null;
+    if (o != null) {
+      if (o instanceof List) {
+        // assume that it contains only strings
+        result = (List) o;
+      } else if (o instanceof CharSequence) {
+        result = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) o));
+      }
+    }
+    return result;
+  }
+
+  Integer toInteger(Object o) {
+    if (o instanceof Integer) {
+      return (Integer) o;
+    }
+    if (o instanceof Long) {
+      return Ints.checkedCast((Long) o);
+    }
+
+    if (o instanceof String) {
+      return Integer.parseInt((String) o);
+    }
+    return null;
+  }
+
+  Double toDouble(Object o) {
+    if (o instanceof Double) {
+      return (Double) o;
+    }
+    if (o instanceof String) {
+      return Double.parseDouble((String) o);
+    }
+    return null;
+  }
+
+
+  Date toDate(Object o) {
+    if (o instanceof Date) {
+      return (Date) o;
+    }
+    if (o instanceof String) {
+      return DateUtils.parseDateTime((String) o);
+    }
+    return null;
+  }
+
+  Boolean toBoolean(Object o) {
+    if (o instanceof Boolean) {
+      return (Boolean) o;
+    }
+    if (o instanceof String) {
+      return Boolean.parseBoolean((String) o);
+    }
+    return null;
+  }
+
+  public void start() {
+    // used to force pico to instantiate the singleton at startup
+  }
+}
index f78b78f13164c9da08c94ad666ff915e814eef3e..7482610dd255634d8938d5c3f2c67c1df4ed558f 100644 (file)
@@ -77,11 +77,11 @@ import org.sonar.server.notifications.NotificationService;
 import org.sonar.server.notifications.reviews.ReviewsNotificationManager;
 import org.sonar.server.plugins.*;
 import org.sonar.server.qualitymodel.DefaultModelManager;
-import org.sonar.server.rule.JRubyRules;
+import org.sonar.server.rule.WebRules;
 import org.sonar.server.rules.ProfilesConsole;
 import org.sonar.server.rules.RulesConsole;
 import org.sonar.server.startup.*;
-import org.sonar.server.text.JRubyText;
+import org.sonar.server.text.WebText;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonar.server.ui.*;
 
@@ -245,15 +245,15 @@ public final class Platform {
     servicesContainer.addSingleton(IssueWorkflow.class);
     servicesContainer.addSingleton(ServerIssueActions.class);
     servicesContainer.addSingleton(ServerIssueFinder.class);
-    servicesContainer.addSingleton(JRubyApiIssues.class);
+    servicesContainer.addSingleton(WebIssuesApi.class);
     servicesContainer.addSingleton(JRubyInternalIssues.class);
 
     // rules
-    servicesContainer.addSingleton(JRubyRules.class);
+    servicesContainer.addSingleton(WebRules.class);
 
     // text
     servicesContainer.addSingleton(MacroInterpreter.class);
-    servicesContainer.addSingleton(JRubyText.class);
+    servicesContainer.addSingleton(WebText.class);
 
     // Notifications
     servicesContainer.addSingleton(EmailSettings.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/JRubyRules.java b/sonar-server/src/main/java/org/sonar/server/rule/JRubyRules.java
deleted file mode 100644 (file)
index bd9e13d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import org.picocontainer.Startable;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.rules.Rule;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.server.platform.UserSession;
-
-/**
- * Used through ruby code <pre>Internal.rules</pre>
- */
-public class JRubyRules implements ServerComponent, Startable {
-
-  private final RuleI18nManager i18n;
-
-  public JRubyRules(RuleI18nManager i18n) {
-    this.i18n = i18n;
-  }
-
-  public String l10nRuleName(Rule rule) {
-    String name = i18n.getName(rule.getRepositoryKey(), rule.getKey(), UserSession.get().locale());
-    if (name == null) {
-      name = rule.getName();
-    }
-    return name;
-  }
-
-  public String l10nRuleDescription(Rule rule) {
-    String desc = i18n.getDescription(rule.getRepositoryKey(), rule.getKey(), UserSession.get().locale());
-    if (desc == null) {
-      desc = rule.getDescription();
-    }
-    return desc;
-  }
-
-  @Override
-  public void start() {
-    // used to force pico to instantiate the singleton at startup
-  }
-
-  @Override
-  public void stop() {
-  }
-}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/WebRules.java b/sonar-server/src/main/java/org/sonar/server/rule/WebRules.java
new file mode 100644 (file)
index 0000000..bb56bd0
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.rule;
+
+import org.picocontainer.Startable;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.rules.Rule;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.server.platform.UserSession;
+
+/**
+ * Used through ruby code <pre>Internal.rules</pre>
+ */
+public class WebRules implements ServerComponent, Startable {
+
+  private final RuleI18nManager i18n;
+
+  public WebRules(RuleI18nManager i18n) {
+    this.i18n = i18n;
+  }
+
+  public String l10nRuleName(Rule rule) {
+    String name = i18n.getName(rule.getRepositoryKey(), rule.getKey(), UserSession.get().locale());
+    if (name == null) {
+      name = rule.getName();
+    }
+    return name;
+  }
+
+  public String l10nRuleDescription(Rule rule) {
+    String desc = i18n.getDescription(rule.getRepositoryKey(), rule.getKey(), UserSession.get().locale());
+    if (desc == null) {
+      desc = rule.getDescription();
+    }
+    return desc;
+  }
+
+  @Override
+  public void start() {
+    // used to force pico to instantiate the singleton at startup
+  }
+
+  @Override
+  public void stop() {
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/text/JRubyText.java b/sonar-server/src/main/java/org/sonar/server/text/JRubyText.java
deleted file mode 100644 (file)
index 7c8fd2a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.text;
-
-import org.apache.commons.lang.StringEscapeUtils;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.source.HtmlSourceDecorator;
-import org.sonar.markdown.Markdown;
-
-import java.util.List;
-
-public class JRubyText implements ServerComponent {
-
-  private final MacroInterpreter macroInterpreter;
-  private final HtmlSourceDecorator sourceDecorator;
-
-  public JRubyText(MacroInterpreter macroInterpreter, HtmlSourceDecorator sourceDecorator) {
-    this.macroInterpreter = macroInterpreter;
-    this.sourceDecorator = sourceDecorator;
-  }
-
-  public String interpretMacros(String text) {
-    return macroInterpreter.interpret(text);
-  }
-
-  public String markdownToHtml(String markdown) {
-    // TODO move HTML escaping to sonar-markdown
-    return Markdown.convertToHtml(StringEscapeUtils.escapeHtml(markdown));
-  }
-
-  public List<String> highlightedSourceLines(long snapshotId) {
-    return sourceDecorator.getDecoratedSourceAsHtml(snapshotId);
-  }
-}
diff --git a/sonar-server/src/main/java/org/sonar/server/text/WebText.java b/sonar-server/src/main/java/org/sonar/server/text/WebText.java
new file mode 100644 (file)
index 0000000..adf198d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.text;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.source.HtmlSourceDecorator;
+import org.sonar.markdown.Markdown;
+
+import java.util.List;
+
+public class WebText implements ServerComponent {
+
+  private final MacroInterpreter macroInterpreter;
+  private final HtmlSourceDecorator sourceDecorator;
+
+  public WebText(MacroInterpreter macroInterpreter, HtmlSourceDecorator sourceDecorator) {
+    this.macroInterpreter = macroInterpreter;
+    this.sourceDecorator = sourceDecorator;
+  }
+
+  public String interpretMacros(String text) {
+    return macroInterpreter.interpret(text);
+  }
+
+  public String markdownToHtml(String markdown) {
+    // TODO move HTML escaping to sonar-markdown
+    return Markdown.convertToHtml(StringEscapeUtils.escapeHtml(markdown));
+  }
+
+  public List<String> highlightedSourceLines(long snapshotId) {
+    return sourceDecorator.getDecoratedSourceAsHtml(snapshotId);
+  }
+}
index 8a2a7b9f9b50d3c8a49aa74a0603a67b3fced91d..cfaf0cf18f4efec17894bed29dc1a180dac4f24b 100644 (file)
@@ -32,7 +32,8 @@ class Api::IssuesController < Api::ApiController
         {
             :securityExclusions => results.securityExclusions,
             :paging => paging_to_json(results.paging),
-            :issues => results.issues.map { |issue| issue_to_json(issue) }
+            :issues => results.issues.map { |issue| issue_to_json(issue) },
+            :rules => results.rules.map { |rule| rule_to_json(rule) }
         }
     )
   end
@@ -206,6 +207,15 @@ class Api::IssuesController < Api::ApiController
     }
   end
 
+  def rule_to_json(rule)
+    l10n_name = Internal.rules.l10nRuleName(rule)
+    l10n_desc = Internal.rules.l10nRuleDescription(rule)
+    json = {:key => rule.getKey()}
+    json[:name] = l10n_name if l10n_name
+    json[:desc] = l10n_desc if l10n_desc
+    json
+  end
+
   def paging_to_json(paging)
     {
         :pageIndex => paging.pageIndex,
index 332bc95fdc228ba1727a5c73d8510ab6eda1bfe7..85717fc270eb7c66eb458301e29792cd8db26018 100644 (file)
@@ -27,15 +27,15 @@ class Internal
   end
 
   def self.issues_api
-    component(Java::OrgSonarApiIssue::JRubyIssues.java_class)
+    component(Java::OrgSonarApiIssue::WebIssues.java_class)
   end
 
   def self.text
-    component(Java::OrgSonarServerText::JRubyText.java_class)
+    component(Java::OrgSonarServerText::WebText.java_class)
   end
 
   def self.rules
-    component(Java::OrgSonarServerRule::JRubyRules.java_class)
+    component(Java::OrgSonarServerRule::WebRules.java_class)
   end
 
   private
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/JRubyApiIssuesTest.java b/sonar-server/src/test/java/org/sonar/server/issue/JRubyApiIssuesTest.java
deleted file mode 100644 (file)
index ed742c8..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.issue;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.issue.IssueFinder;
-import org.sonar.api.issue.IssueQuery;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.web.UserRole;
-
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
-import static java.util.Arrays.asList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
-
-public class JRubyApiIssuesTest {
-
-  IssueFinder finder = mock(IssueFinder.class);
-  JRubyApiIssues facade = new JRubyApiIssues(finder);
-
-  @Test
-  public void test_find() throws Exception {
-    facade.find(ImmutableMap.<String, Object>of("issueKeys", Lists.newArrayList("ABCDE")));
-    verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() {
-      @Override
-      public boolean matches(Object o) {
-        return ((IssueQuery) o).issueKeys().contains("ABCDE");
-      }
-    }), anyInt(), eq(UserRole.CODEVIEWER));
-  }
-
-  @Test
-  public void should_create_query_from_parameters() {
-    Map<String, Object> map = newHashMap();
-    map.put("issueKeys", newArrayList("ABCDE1234"));
-    map.put("severities", newArrayList("MAJOR", "MINOR"));
-    map.put("statuses", newArrayList("CLOSED"));
-    map.put("resolutions", newArrayList("FALSE-POSITIVE"));
-    map.put("components", newArrayList("org.apache"));
-    map.put("componentRoots", newArrayList("org.sonar"));
-    map.put("userLogins", newArrayList("marilyn"));
-    map.put("assignees", newArrayList("joanna"));
-    map.put("assigned", true);
-    map.put("createdAfter", "2013-04-16T09:08:24+0200");
-    map.put("createdBefore", "2013-04-17T09:08:24+0200");
-    map.put("rules", "squid:AvoidCycle,findbugs:NullReference");
-    map.put("pageSize", 10l);
-    map.put("pageIndex", 50);
-
-    IssueQuery query = new JRubyApiIssues(finder).toQuery(map);
-    assertThat(query.issueKeys()).containsOnly("ABCDE1234");
-    assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
-    assertThat(query.statuses()).containsOnly("CLOSED");
-    assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
-    assertThat(query.components()).containsOnly("org.apache");
-    assertThat(query.componentRoots()).containsOnly("org.sonar");
-    assertThat(query.userLogins()).containsOnly("marilyn");
-    assertThat(query.assignees()).containsOnly("joanna");
-    assertThat(query.assigned()).isTrue();
-    assertThat(query.rules()).hasSize(2);
-    assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
-    assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
-    assertThat(query.pageSize()).isEqualTo(10);
-    assertThat(query.pageIndex()).isEqualTo(50);
-  }
-
-  @Test
-  public void should_parse_list_of_rules() {
-    assertThat(JRubyApiIssues.toRules(null)).isNull();
-    assertThat(JRubyApiIssues.toRules("")).isEmpty();
-    assertThat(JRubyApiIssues.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle"));
-    assertThat(JRubyApiIssues.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
-    assertThat(JRubyApiIssues.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
-  }
-
-  @Test
-  public void should_parse_list_of_strings() {
-    assertThat(JRubyApiIssues.toStrings(null)).isNull();
-    assertThat(JRubyApiIssues.toStrings("")).isEmpty();
-    assertThat(JRubyApiIssues.toStrings("foo")).containsOnly("foo");
-    assertThat(JRubyApiIssues.toStrings("foo,bar")).containsOnly("foo", "bar");
-    assertThat(JRubyApiIssues.toStrings(asList("foo", "bar"))).containsOnly("foo", "bar");
-
-  }
-
-  @Test
-  public void should_start() throws Exception {
-    facade.start();
-    // nothing is done
-    verifyZeroInteractions(finder);
-  }
-}
index d2090f4da40feb899bbc37d84dde48db609270f6..1bd38633d773bbc24b441d7c00893aba53f5363f 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.server.issue;
 
 import org.apache.ibatis.session.SqlSession;
-import org.junit.Before;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -56,30 +55,18 @@ import static org.mockito.Mockito.*;
 
 public class ServerIssueFinderTest {
 
-  MyBatis mybatis;
-  ServerIssueFinder finder;
-
-  IssueDao issueDao;
-  AuthorizationDao authorizationDao;
-  DefaultRuleFinder ruleFinder;
-  ResourceDao resourceDao;
-  ActionPlanIssueDao actionPlanIssueDao;
-
-  @Before
-  public void before() {
-    mybatis = mock(MyBatis.class);
-    issueDao = mock(IssueDao.class);
-    authorizationDao = mock(AuthorizationDao.class);
-    ruleFinder = mock(DefaultRuleFinder.class);
-    resourceDao = mock(ResourceDao.class);
-    actionPlanIssueDao = mock(ActionPlanIssueDao.class);
-    finder = new ServerIssueFinder(mybatis, issueDao, authorizationDao, ruleFinder, resourceDao, actionPlanIssueDao);
-  }
+  MyBatis mybatis = mock(MyBatis.class);
+  IssueDao issueDao = mock(IssueDao.class);
+  AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
+  DefaultRuleFinder ruleFinder = mock(DefaultRuleFinder.class);
+  ResourceDao resourceDao = mock(ResourceDao.class);
+  ActionPlanIssueDao actionPlanIssueDao = mock(ActionPlanIssueDao.class);
+  ServerIssueFinder finder = new ServerIssueFinder(mybatis, issueDao, authorizationDao, ruleFinder, resourceDao, actionPlanIssueDao);
 
   @Test
   public void should_find_issues() {
     grantAccessRights();
-    IssueQuery issueQuery = mock(IssueQuery.class);
+    IssueQuery query = IssueQuery.builder().build();
 
     IssueDto issue1 = new IssueDto().setId(1L).setRuleId(50).setResourceId(123)
       .setComponentKey_unit_test_only("Action.java")
@@ -90,10 +77,10 @@ public class ServerIssueFinderTest {
       .setRuleKey_unit_test_only("squid", "AvoidCycle")
       .setStatus("OPEN").setResolution("OPEN");
     List<IssueDto> dtoList = newArrayList(issue1, issue2);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(dtoList);
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(dtoList);
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList);
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
     assertThat(results.issues()).hasSize(2);
     Issue issue = results.issues().iterator().next();
     assertThat(issue.componentKey()).isEqualTo("Action.java");
@@ -103,8 +90,7 @@ public class ServerIssueFinderTest {
 
   @Test
   public void should_find_only_authorized_issues() {
-    IssueQuery issueQuery = mock(IssueQuery.class);
-    when(issueQuery.pageSize()).thenReturn(100);
+    IssueQuery query = IssueQuery.builder().pageSize(100).build();
 
     IssueDto issue1 = new IssueDto().setId(1L).setRuleId(50).setResourceId(123)
       .setComponentKey_unit_test_only("Action.java")
@@ -115,11 +101,11 @@ public class ServerIssueFinderTest {
       .setRuleKey_unit_test_only("squid", "AvoidCycle")
       .setStatus("OPEN").setResolution("OPEN");
     List<IssueDto> dtoList = newArrayList(issue1, issue2);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(dtoList);
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(dtoList);
     when(authorizationDao.keepAuthorizedComponentIds(anySet(), anyInt(), anyString(), any(SqlSession.class))).thenReturn(newHashSet(123));
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(newArrayList(issue1));
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
 
     verify(issueDao).selectByIds(eq(newHashSet(1L)), any(SqlSession.class));
     assertThat(results.securityExclusions()).isTrue();
@@ -129,9 +115,7 @@ public class ServerIssueFinderTest {
   public void should_find_paginate_result() {
     grantAccessRights();
 
-    IssueQuery issueQuery = mock(IssueQuery.class);
-    when(issueQuery.pageSize()).thenReturn(1);
-    when(issueQuery.pageIndex()).thenReturn(1);
+    IssueQuery query = IssueQuery.builder().pageSize(1).pageIndex(1).build();
 
     IssueDto issue1 = new IssueDto().setId(1L).setRuleId(50).setResourceId(123)
       .setComponentKey_unit_test_only("Action.java")
@@ -142,10 +126,10 @@ public class ServerIssueFinderTest {
       .setRuleKey_unit_test_only("squid", "AvoidCycle")
       .setStatus("OPEN").setResolution("OPEN");
     List<IssueDto> dtoList = newArrayList(issue1, issue2);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(dtoList);
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(dtoList);
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList);
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
     assertThat(results.paging().offset()).isEqualTo(0);
     assertThat(results.paging().total()).isEqualTo(2);
     assertThat(results.paging().pages()).isEqualTo(2);
@@ -174,7 +158,7 @@ public class ServerIssueFinderTest {
     when(ruleFinder.findByIds(anyCollection())).thenReturn(newArrayList(rule));
 
     grantAccessRights();
-    IssueQuery issueQuery = mock(IssueQuery.class);
+    IssueQuery query = IssueQuery.builder().build();
 
     IssueDto issue1 = new IssueDto().setId(1L).setRuleId(50).setResourceId(123)
       .setComponentKey_unit_test_only("Action.java")
@@ -185,10 +169,10 @@ public class ServerIssueFinderTest {
       .setRuleKey_unit_test_only("squid", "AvoidCycle")
       .setStatus("OPEN").setResolution("OPEN");
     List<IssueDto> dtoList = newArrayList(issue1, issue2);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(dtoList);
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(dtoList);
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList);
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
     assertThat(results.issues()).hasSize(2);
     Issue issue = results.issues().iterator().next();
     assertThat(results.issues()).hasSize(2);
@@ -202,7 +186,7 @@ public class ServerIssueFinderTest {
     when(resourceDao.findByIds(anyCollection())).thenReturn(newArrayList(component));
 
     grantAccessRights();
-    IssueQuery issueQuery = mock(IssueQuery.class);
+    IssueQuery query = IssueQuery.builder().build();
 
     IssueDto issue1 = new IssueDto().setId(1L).setRuleId(50).setResourceId(123)
       .setComponentKey_unit_test_only("Action.java")
@@ -213,11 +197,11 @@ public class ServerIssueFinderTest {
       .setRuleKey_unit_test_only("squid", "AvoidCycle")
       .setStatus("OPEN").setResolution("OPEN");
     List<IssueDto> dtoList = newArrayList(issue1, issue2);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(dtoList);
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(dtoList);
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList);
 
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
     assertThat(results.issues()).hasSize(2);
     Issue issue = results.issues().iterator().next();
     assertThat(results.issues()).hasSize(2);
@@ -231,7 +215,7 @@ public class ServerIssueFinderTest {
     ActionPlanIssueDto actionPlanIssueDto2 = new ActionPlanIssueDto().setIssueId(2L).setKee("B").setName("Long term");
 
     grantAccessRights();
-    IssueQuery issueQuery = mock(IssueQuery.class);
+    IssueQuery query = IssueQuery.builder().build();
 
     IssueDto issue1 = new IssueDto().setId(1L).setRuleId(50).setResourceId(123).setKey("ABC")
       .setComponentKey_unit_test_only("Action.java")
@@ -242,13 +226,13 @@ public class ServerIssueFinderTest {
       .setRuleKey_unit_test_only("squid", "AvoidCycle")
       .setStatus("OPEN").setResolution("OPEN");
     List<IssueDto> dtoList = newArrayList(issue1, issue2);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(dtoList);
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(dtoList);
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList);
 
     when(actionPlanIssueDao.findByIssueIds(anyCollection(), any(SqlSession.class))).thenReturn(newArrayList(actionPlanIssueDto1, actionPlanIssueDto2));
 
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
     assertThat(results.issues()).hasSize(2);
     Issue issue = results.issues().iterator().next();
     assertThat(results.issues()).hasSize(2);
@@ -258,12 +242,12 @@ public class ServerIssueFinderTest {
   @Test
   public void should_get_empty_result_when_no_issue() {
     grantAccessRights();
-    IssueQuery issueQuery = mock(IssueQuery.class);
-    when(issueDao.selectIssueIdsAndComponentsId(eq(issueQuery), any(SqlSession.class))).thenReturn(Collections.<IssueDto>emptyList());
+    IssueQuery query = IssueQuery.builder().build();
+    when(issueDao.selectIssueIdsAndComponentsId(eq(query), any(SqlSession.class))).thenReturn(Collections.<IssueDto>emptyList());
     when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(Collections.<IssueDto>emptyList());
 
 
-    IssueFinder.Results results = finder.find(issueQuery, null, UserRole.USER);
+    IssueFinder.Results results = finder.find(query, null, UserRole.USER);
     assertThat(results.issues()).isEmpty();
     assertThat(results.rules()).isEmpty();
     assertThat(results.components()).isEmpty();
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/WebIssuesApiTest.java b/sonar-server/src/test/java/org/sonar/server/issue/WebIssuesApiTest.java
new file mode 100644 (file)
index 0000000..1ba994b
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.issue;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.sonar.api.issue.IssueFinder;
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.web.UserRole;
+
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Arrays.asList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+public class WebIssuesApiTest {
+
+  IssueFinder finder = mock(IssueFinder.class);
+  WebIssuesApi facade = new WebIssuesApi(finder);
+
+  @Test
+  public void test_find() throws Exception {
+    facade.find(ImmutableMap.<String, Object>of("issueKeys", Lists.newArrayList("ABCDE")));
+    verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() {
+      @Override
+      public boolean matches(Object o) {
+        return ((IssueQuery) o).issueKeys().contains("ABCDE");
+      }
+    }), anyInt(), eq(UserRole.CODEVIEWER));
+  }
+
+  @Test
+  public void should_create_query_from_parameters() {
+    Map<String, Object> map = newHashMap();
+    map.put("issueKeys", newArrayList("ABCDE1234"));
+    map.put("severities", newArrayList("MAJOR", "MINOR"));
+    map.put("statuses", newArrayList("CLOSED"));
+    map.put("resolutions", newArrayList("FALSE-POSITIVE"));
+    map.put("components", newArrayList("org.apache"));
+    map.put("componentRoots", newArrayList("org.sonar"));
+    map.put("userLogins", newArrayList("marilyn"));
+    map.put("assignees", newArrayList("joanna"));
+    map.put("assigned", true);
+    map.put("createdAfter", "2013-04-16T09:08:24+0200");
+    map.put("createdBefore", "2013-04-17T09:08:24+0200");
+    map.put("rules", "squid:AvoidCycle,findbugs:NullReference");
+    map.put("pageSize", 10l);
+    map.put("pageIndex", 50);
+
+    IssueQuery query = new WebIssuesApi(finder).toQuery(map);
+    assertThat(query.issueKeys()).containsOnly("ABCDE1234");
+    assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
+    assertThat(query.statuses()).containsOnly("CLOSED");
+    assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
+    assertThat(query.components()).containsOnly("org.apache");
+    assertThat(query.componentRoots()).containsOnly("org.sonar");
+    assertThat(query.userLogins()).containsOnly("marilyn");
+    assertThat(query.assignees()).containsOnly("joanna");
+    assertThat(query.assigned()).isTrue();
+    assertThat(query.rules()).hasSize(2);
+    assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
+    assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
+    assertThat(query.pageSize()).isEqualTo(10);
+    assertThat(query.pageIndex()).isEqualTo(50);
+  }
+
+  @Test
+  public void should_parse_list_of_rules() {
+    assertThat(WebIssuesApi.toRules(null)).isNull();
+    assertThat(WebIssuesApi.toRules("")).isEmpty();
+    assertThat(WebIssuesApi.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle"));
+    assertThat(WebIssuesApi.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
+    assertThat(WebIssuesApi.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
+  }
+
+  @Test
+  public void should_parse_list_of_strings() {
+    assertThat(WebIssuesApi.toStrings(null)).isNull();
+    assertThat(WebIssuesApi.toStrings("")).isEmpty();
+    assertThat(WebIssuesApi.toStrings("foo")).containsOnly("foo");
+    assertThat(WebIssuesApi.toStrings("foo,bar")).containsOnly("foo", "bar");
+    assertThat(WebIssuesApi.toStrings(asList("foo", "bar"))).containsOnly("foo", "bar");
+
+  }
+
+  @Test
+  public void should_start() throws Exception {
+    facade.start();
+    // nothing is done
+    verifyZeroInteractions(finder);
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/JRubyRulesTest.java b/sonar-server/src/test/java/org/sonar/server/rule/JRubyRulesTest.java
deleted file mode 100644 (file)
index b84a2bd..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.rule;
-
-import org.junit.Test;
-import org.sonar.api.rules.Rule;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.server.platform.UserSession;
-
-import java.util.Locale;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class JRubyRulesTest {
-
-  RuleI18nManager i18n = mock(RuleI18nManager.class);
-  JRubyRules facade = new JRubyRules(i18n);
-
-  @Test
-  public void should_get_localized_rule_name() {
-    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
-    when(i18n.getName("squid", "AvoidCycle", Locale.FRENCH)).thenReturn("Eviter les cycles");
-
-    String name = facade.l10nRuleName(new Rule("squid", "AvoidCycle"));
-    assertThat(name).isEqualTo("Eviter les cycles");
-  }
-
-  @Test
-  public void should_get_raw_name_if_no_l10n_name() throws Exception {
-    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
-    when(i18n.getName("squid", "AvoidCycle", Locale.FRENCH)).thenReturn(null);
-
-    Rule rule = new Rule("squid", "AvoidCycle");
-    rule.setName("Avoid cycles");
-    String name = facade.l10nRuleName(rule);
-    assertThat(name).isEqualTo("Avoid cycles");
-  }
-
-  @Test
-  public void should_get_localized_rule_description() {
-    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
-    when(i18n.getDescription("squid", "AvoidCycle", Locale.FRENCH)).thenReturn("Les cycles sont le mal");
-
-    String desc = facade.l10nRuleDescription(new Rule("squid", "AvoidCycle"));
-    assertThat(desc).isEqualTo("Les cycles sont le mal");
-  }
-
-  @Test
-  public void should_get_raw_description_if_no_l10n_description() throws Exception {
-    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
-    when(i18n.getDescription("squid", "AvoidCycle", Locale.FRENCH)).thenReturn(null);
-
-    Rule rule = new Rule("squid", "AvoidCycle");
-    rule.setDescription("Cycles are evil");
-    String desc = facade.l10nRuleDescription(rule);
-    assertThat(desc).isEqualTo("Cycles are evil");
-  }
-
-  @Test
-  public void just_for_fun_and_coverage() throws Exception {
-    facade.start();
-    facade.stop();
-    // do not fail
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/WebRulesTest.java b/sonar-server/src/test/java/org/sonar/server/rule/WebRulesTest.java
new file mode 100644 (file)
index 0000000..3900100
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.rule;
+
+import org.junit.Test;
+import org.sonar.api.rules.Rule;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.server.platform.UserSession;
+
+import java.util.Locale;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class WebRulesTest {
+
+  RuleI18nManager i18n = mock(RuleI18nManager.class);
+  WebRules facade = new WebRules(i18n);
+
+  @Test
+  public void should_get_localized_rule_name() {
+    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
+    when(i18n.getName("squid", "AvoidCycle", Locale.FRENCH)).thenReturn("Eviter les cycles");
+
+    String name = facade.l10nRuleName(new Rule("squid", "AvoidCycle"));
+    assertThat(name).isEqualTo("Eviter les cycles");
+  }
+
+  @Test
+  public void should_get_raw_name_if_no_l10n_name() throws Exception {
+    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
+    when(i18n.getName("squid", "AvoidCycle", Locale.FRENCH)).thenReturn(null);
+
+    Rule rule = new Rule("squid", "AvoidCycle");
+    rule.setName("Avoid cycles");
+    String name = facade.l10nRuleName(rule);
+    assertThat(name).isEqualTo("Avoid cycles");
+  }
+
+  @Test
+  public void should_get_localized_rule_description() {
+    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
+    when(i18n.getDescription("squid", "AvoidCycle", Locale.FRENCH)).thenReturn("Les cycles sont le mal");
+
+    String desc = facade.l10nRuleDescription(new Rule("squid", "AvoidCycle"));
+    assertThat(desc).isEqualTo("Les cycles sont le mal");
+  }
+
+  @Test
+  public void should_get_raw_description_if_no_l10n_description() throws Exception {
+    UserSession.set(new UserSession(123, "emmerik", Locale.FRENCH));
+    when(i18n.getDescription("squid", "AvoidCycle", Locale.FRENCH)).thenReturn(null);
+
+    Rule rule = new Rule("squid", "AvoidCycle");
+    rule.setDescription("Cycles are evil");
+    String desc = facade.l10nRuleDescription(rule);
+    assertThat(desc).isEqualTo("Cycles are evil");
+  }
+
+  @Test
+  public void just_for_fun_and_coverage() throws Exception {
+    facade.start();
+    facade.stop();
+    // do not fail
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/text/JRubyTextTest.java b/sonar-server/src/test/java/org/sonar/server/text/JRubyTextTest.java
deleted file mode 100644 (file)
index feb71d9..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.text;
-
-import org.junit.Test;
-import org.sonar.core.source.HtmlSourceDecorator;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.*;
-
-public class JRubyTextTest {
-
-  MacroInterpreter macroInterpreter = mock(MacroInterpreter.class);
-  HtmlSourceDecorator sourceDecorator = mock(HtmlSourceDecorator.class);
-  JRubyText text = new JRubyText(macroInterpreter, sourceDecorator);
-
-  @Test
-  public void interpretMacros() throws Exception {
-    text.interpretMacros("text with macros");
-    verify(macroInterpreter, times(1)).interpret("text with macros");
-    verifyZeroInteractions(sourceDecorator);
-  }
-
-  @Test
-  public void markdownToHtml() throws Exception {
-    String html = text.markdownToHtml("some *markdown*");
-    assertThat(html).isEqualTo("some <em>markdown</em>");
-  }
-
-  @Test
-  public void should_escape_markdown_input() throws Exception {
-    String html = text.markdownToHtml("a > b");
-    assertThat(html).isEqualTo("a &gt; b");
-  }
-
-  @Test
-  public void highlightedSourceLines() throws Exception {
-    text.highlightedSourceLines(123L);
-    verify(sourceDecorator, times(1)).getDecoratedSourceAsHtml(123L);
-    verifyZeroInteractions(macroInterpreter);
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/text/WebTextTest.java b/sonar-server/src/test/java/org/sonar/server/text/WebTextTest.java
new file mode 100644 (file)
index 0000000..ffb168f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.text;
+
+import org.junit.Test;
+import org.sonar.core.source.HtmlSourceDecorator;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class WebTextTest {
+
+  MacroInterpreter macroInterpreter = mock(MacroInterpreter.class);
+  HtmlSourceDecorator sourceDecorator = mock(HtmlSourceDecorator.class);
+  WebText text = new WebText(macroInterpreter, sourceDecorator);
+
+  @Test
+  public void interpretMacros() throws Exception {
+    text.interpretMacros("text with macros");
+    verify(macroInterpreter, times(1)).interpret("text with macros");
+    verifyZeroInteractions(sourceDecorator);
+  }
+
+  @Test
+  public void markdownToHtml() throws Exception {
+    String html = text.markdownToHtml("some *markdown*");
+    assertThat(html).isEqualTo("some <em>markdown</em>");
+  }
+
+  @Test
+  public void should_escape_markdown_input() throws Exception {
+    String html = text.markdownToHtml("a > b");
+    assertThat(html).isEqualTo("a &gt; b");
+  }
+
+  @Test
+  public void highlightedSourceLines() throws Exception {
+    text.highlightedSourceLines(123L);
+    verify(sourceDecorator, times(1)).getDecoratedSourceAsHtml(123L);
+    verifyZeroInteractions(macroInterpreter);
+  }
+}