]> source.dussan.org Git - sonarqube.git/commitdiff
Move measure filter classes from sonar-core to sonar-server
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 19 May 2014 08:33:08 +0000 (10:33 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 19 May 2014 08:33:08 +0000 (10:33 +0200)
47 files changed:
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterCondition.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterContext.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterEngine.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterResult.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterRow.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java [deleted file]
sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSql.java [deleted file]
sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterConditionTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterContextTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterEngineTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterExecutorTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterTest.java [deleted file]
sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/escape_percent_and_underscore_when_filter_by_component_name_or_key.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/ignore_person_measures.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/ignore_quality_model_measures.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/shared.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/sort_by_alert.xml [deleted file]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilter.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterCondition.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterContext.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterEngine.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterExecutor.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterFactory.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterResult.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterRow.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSort.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/package-info.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/measure/ws/package-info.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterConditionTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterContextTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterEngineTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterExecutorTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterFactoryTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterTest.java [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/escape_percent_and_underscore_when_filter_by_component_name_or_key.xml [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/ignore_person_measures.xml [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/ignore_quality_model_measures.xml [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/shared.xml [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/sort_by_alert.xml [new file with mode: 0644]

diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilter.java
deleted file mode 100644 (file)
index 3b27ec5..0000000
+++ /dev/null
@@ -1,202 +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.core.measure;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Qualifiers;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-public class MeasureFilter {
-
-  // conditions on resources
-  private String baseResourceKey;
-
-  // only if baseResourceKey or baseResourceId are set
-  private boolean onBaseResourceChildren = false;
-
-  private List<String> resourceScopes = Collections.emptyList();
-  private List<String> resourceQualifiers = Collections.emptyList();
-  private String resourceKey = null;
-  private String resourceName = null;
-  private Date fromDate = null, toDate = null;
-  private boolean userFavourites = false;
-
-  // conditions on measures
-  private List<MeasureFilterCondition> measureConditions = Lists.newArrayList();
-
-  // sort
-  private MeasureFilterSort sort = new MeasureFilterSort();
-
-  public String getBaseResourceKey() {
-    return baseResourceKey;
-  }
-
-  public MeasureFilter setBaseResourceKey(String s) {
-    this.baseResourceKey = s;
-    return this;
-  }
-
-  public MeasureFilter setOnBaseResourceChildren(boolean b) {
-    this.onBaseResourceChildren = b;
-    return this;
-  }
-
-  public boolean isOnBaseResourceChildren() {
-    return onBaseResourceChildren;
-  }
-
-  public MeasureFilter setResourceScopes(@Nullable List<String> list) {
-    this.resourceScopes = sanitize(list);
-    return this;
-  }
-
-  public MeasureFilter setResourceQualifiers(@Nullable List<String> list) {
-    this.resourceQualifiers = sanitize(list);
-    if (resourceQualifiers.contains(Qualifiers.FILE)) {
-      resourceQualifiers.add(Qualifiers.CLASS);
-    }
-    if (resourceQualifiers.contains(Qualifiers.DIRECTORY)) {
-      resourceQualifiers.add(Qualifiers.PACKAGE);
-    }
-    return this;
-  }
-
-  public MeasureFilter setUserFavourites(boolean b) {
-    this.userFavourites = b;
-    return this;
-  }
-
-  public boolean isOnFavourites() {
-    return userFavourites;
-  }
-
-  public String getResourceName() {
-    return resourceName;
-  }
-
-  public MeasureFilter setResourceName(String s) {
-    this.resourceName = s;
-    return this;
-  }
-
-  public String getResourceKey() {
-    return resourceKey;
-  }
-
-  public MeasureFilter setResourceKey(String s) {
-    this.resourceKey = s;
-    return this;
-  }
-
-  public MeasureFilter addCondition(MeasureFilterCondition condition) {
-    this.measureConditions.add(condition);
-    return this;
-  }
-
-  public MeasureFilter setSortOn(MeasureFilterSort.Field sortField) {
-    this.sort.setField(sortField);
-    return this;
-  }
-
-  public MeasureFilter setSortAsc(boolean b) {
-    this.sort.setAsc(b);
-    return this;
-  }
-
-  public MeasureFilter setSortOnMetric(Metric m) {
-    this.sort.setField(MeasureFilterSort.Field.METRIC);
-    this.sort.setMetric(m);
-    return this;
-  }
-
-  public MeasureFilter setSortOnPeriod(int period) {
-    this.sort.setPeriod(period);
-    return this;
-  }
-
-  public MeasureFilter setFromDate(@Nullable Date d) {
-    this.fromDate = d;
-    return this;
-  }
-
-  public MeasureFilter setToDate(@Nullable Date d) {
-    this.toDate = d;
-    return this;
-  }
-
-  @CheckForNull
-  public Date getFromDate() {
-    return fromDate;
-  }
-
-  @CheckForNull
-  public Date getToDate() {
-    return toDate;
-  }
-
-  public List<String> getResourceScopes() {
-    return resourceScopes;
-  }
-
-  public List<String> getResourceQualifiers() {
-    return resourceQualifiers;
-  }
-
-  public List<MeasureFilterCondition> getMeasureConditions() {
-    return measureConditions;
-  }
-
-  MeasureFilterSort sort() {
-    return sort;
-  }
-
-  public boolean isEmpty() {
-    return resourceQualifiers.isEmpty() && resourceScopes.isEmpty() && StringUtils.isEmpty(baseResourceKey) && !userFavourites;
-  }
-
-  @VisibleForTesting
-  static List<String> sanitize(@Nullable List<String> list) {
-    return isEmptyList(list) ? Collections.<String> emptyList() : Lists.newArrayList(list);
-  }
-
-  private static boolean isEmptyList(@Nullable List<String> list) {
-    boolean blank = false;
-    if (list == null || list.isEmpty() || (list.size() == 1 && Strings.isNullOrEmpty(list.get(0)))) {
-      blank = true;
-    }
-    return blank;
-  }
-
-  @Override
-  public String toString() {
-    return ReflectionToStringBuilder.toString(this);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterCondition.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterCondition.java
deleted file mode 100644 (file)
index 80b80fc..0000000
+++ /dev/null
@@ -1,133 +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.core.measure;
-
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.measures.Metric;
-
-public class MeasureFilterCondition {
-  public enum Operator {
-    EQUALS("eq", "="), GREATER("gt", ">"), GREATER_OR_EQUALS("gte", ">="), LESS("lt", "<"), LESS_OR_EQUALS("lte", "<="), IN("in", "IN");
-
-    private String code;
-    private String sql;
-
-    private Operator(String code, String sql) {
-      this.code = code;
-      this.sql = sql;
-    }
-
-    public String getSql() {
-      return sql;
-    }
-
-    public static Operator fromCode(String code) {
-      for (Operator operator : values()) {
-        if (operator.code.equals(code)) {
-          return operator;
-        }
-      }
-      throw new IllegalArgumentException("Unknown operator code: " + code);
-    }
-  }
-
-  private final Metric metric;
-  private final Operator operator;
-  private final double value;
-  private final String textValue;
-  private Integer period = null;
-
-  public MeasureFilterCondition(Metric metric, Operator operator, double value) {
-    this.metric = metric;
-    this.operator = operator;
-    this.value = value;
-    this.textValue = null;
-  }
-
-  public MeasureFilterCondition(Metric metric, Operator operator, String textValue) {
-    this.metric = metric;
-    this.operator = operator;
-    this.value = 0;
-    this.textValue = textValue;
-  }
-
-  public MeasureFilterCondition setPeriod(Integer period) {
-    this.period = period;
-    return this;
-  }
-
-  public Metric metric() {
-    return metric;
-  }
-
-  public Operator operator() {
-    return operator;
-  }
-
-  public double value() {
-    return value;
-  }
-
-  public String textValue() {
-    return textValue;
-  }
-
-  public Integer period() {
-    return period;
-  }
-
-  StringBuilder appendSqlColumn(StringBuilder sb, int conditionIndex) {
-    sb.append("pmcond").append(conditionIndex);
-    if (period != null) {
-      sb.append(".variation_value_").append(period).toString();
-    } else if (textValue == null) {
-      sb.append(".value");
-    } else {
-      sb.append(".text_value");
-    }
-    return sb;
-  }
-
-  StringBuilder appendSqlCondition(StringBuilder sql, int conditionIndex) {
-    String table = "pmcond" + conditionIndex;
-    sql.append(" ").append(table).append(".metric_id=");
-    sql.append(metric.getId());
-    sql.append(" AND ");
-    appendSqlColumn(sql, conditionIndex);
-    sql.append(" ").append(operator.getSql()).append(" ");
-    if (textValue == null) {
-      sql.append(value);
-    } else {
-      sql.append(textValue);
-    }
-    sql.append(" AND ");
-    sql.append(table).append(".rule_id IS NULL AND ");
-    sql.append(table).append(".rule_priority IS NULL AND ");
-    sql.append(table).append(".characteristic_id IS NULL AND ");
-    sql.append(table).append(".person_id IS NULL ");
-    return sql;
-  }
-
-  @Override
-  public String toString() {
-    return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterContext.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterContext.java
deleted file mode 100644 (file)
index f291eb9..0000000
+++ /dev/null
@@ -1,78 +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.core.measure;
-
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.core.resource.SnapshotDto;
-
-import javax.annotation.Nullable;
-
-class MeasureFilterContext {
-  private Long userId = null;
-  private SnapshotDto baseSnapshot = null;
-  private String sql;
-  private String data;
-
-  Long getUserId() {
-    return userId;
-  }
-
-  MeasureFilterContext setUserId(@Nullable Long userId) {
-    this.userId = userId;
-    return this;
-  }
-
-  SnapshotDto getBaseSnapshot() {
-    return baseSnapshot;
-  }
-
-  MeasureFilterContext setBaseSnapshot(@Nullable SnapshotDto baseSnapshot) {
-    this.baseSnapshot = baseSnapshot;
-    return this;
-  }
-
-  String getSql() {
-    return sql;
-  }
-
-  MeasureFilterContext setSql(String sql) {
-    this.sql = sql;
-    return this;
-  }
-
-  String getData() {
-    return data;
-  }
-
-  MeasureFilterContext setData(String data) {
-    this.data = data;
-    return this;
-  }
-
-  @Override
-  public String toString() {
-    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
-      .append("filter", data)
-      .append("sql", sql)
-      .append("user", userId)
-      .toString();
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterEngine.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterEngine.java
deleted file mode 100644 (file)
index 3e3e4a1..0000000
+++ /dev/null
@@ -1,86 +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.core.measure;
-
-import com.google.common.base.Joiner;
-import org.apache.commons.lang.SystemUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.profiling.Profiling;
-import org.sonar.core.profiling.Profiling.Level;
-import org.sonar.core.profiling.StopWatch;
-
-import javax.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
-
-public class MeasureFilterEngine implements ServerComponent {
-
-  private static final Logger LOG = LoggerFactory.getLogger("org.sonar.MEASURE_FILTER");
-
-  private final MeasureFilterFactory factory;
-  private final MeasureFilterExecutor executor;
-  private final Profiling profiling;
-
-  public MeasureFilterEngine(MeasureFilterFactory factory, MeasureFilterExecutor executor, Profiling profiling) {
-    this.executor = executor;
-    this.factory = factory;
-    this.profiling = profiling;
-  }
-
-  public MeasureFilterResult execute(Map<String, Object> filterMap, @Nullable Long userId) {
-    StopWatch watch = profiling.start("measures", Level.BASIC);
-    StopWatch sqlWatch = null;
-    MeasureFilterResult result = new MeasureFilterResult();
-    MeasureFilterContext context = new MeasureFilterContext();
-    context.setUserId(userId);
-    context.setData(String.format("{%s}", Joiner.on('|').withKeyValueSeparator("=").join(filterMap)));
-    try {
-      MeasureFilter filter = factory.create(filterMap);
-      sqlWatch = profiling.start("sql", Level.FULL);
-      List<MeasureFilterRow> rows = executor.execute(filter, context);
-      result.setRows(rows);
-
-    } catch (NumberFormatException e) {
-      result.setError(MeasureFilterResult.Error.VALUE_SHOULD_BE_A_NUMBER);
-      LOG.debug("Value selected for the metric should be a number: " + context);
-    } catch (Exception e) {
-      result.setError(MeasureFilterResult.Error.UNKNOWN);
-      LOG.error("Fail to execute measure filter: " + context, e);
-    } finally {
-      if (sqlWatch != null) {
-        sqlWatch.stop(context.getSql());
-      }
-      watch.stop(log(context, result));
-    }
-    return result;
-  }
-
-  private String log(MeasureFilterContext context, MeasureFilterResult result) {
-    StringBuilder log = new StringBuilder();
-    log.append(SystemUtils.LINE_SEPARATOR);
-    log.append("request: ").append(context.getData()).append(SystemUtils.LINE_SEPARATOR);
-    log.append(" result: ").append(result.toString());
-    return log.toString();
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java
deleted file mode 100644 (file)
index 713280e..0000000
+++ /dev/null
@@ -1,114 +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.core.measure;
-
-import com.google.common.base.Strings;
-import org.apache.commons.dbutils.DbUtils;
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.persistence.Database;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.resource.ResourceDao;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-
-public class MeasureFilterExecutor implements ServerComponent {
-
-  private MyBatis mybatis;
-  private Database database;
-  private ResourceDao resourceDao;
-
-  public MeasureFilterExecutor(MyBatis mybatis, Database database, ResourceDao resourceDao) {
-    this.mybatis = mybatis;
-    this.database = database;
-    this.resourceDao = resourceDao;
-  }
-
-  public List<MeasureFilterRow> execute(MeasureFilter filter, MeasureFilterContext context) throws SQLException {
-    if (filter.isEmpty()) {
-      return Collections.emptyList();
-    }
-
-    List<MeasureFilterRow> rows;
-    SqlSession session = null;
-    Connection connection = null;
-    try {
-      session = mybatis.openSession(false);
-      prepareContext(context, filter, session);
-
-      if (isValid(filter, context)) {
-        MeasureFilterSql sql = new MeasureFilterSql(database, filter, context);
-        context.setSql(sql.sql());
-        connection = session.getConnection();
-        rows = sql.execute(connection);
-      } else {
-        rows = Collections.emptyList();
-      }
-    } finally {
-      MyBatis.closeQuietly(session);
-      // connection is supposed to be closed by the session
-      DbUtils.closeQuietly(connection);
-    }
-
-    return rows;
-  }
-
-  private void prepareContext(MeasureFilterContext context, MeasureFilter filter, SqlSession session) {
-    if (filter.getBaseResourceKey() != null) {
-      context.setBaseSnapshot(resourceDao.getLastSnapshot(filter.getBaseResourceKey(), session));
-    }
-  }
-
-  static boolean isValid(MeasureFilter filter, MeasureFilterContext context) {
-    boolean valid = Strings.isNullOrEmpty(filter.getBaseResourceKey()) || context.getBaseSnapshot()!=null;
-    valid &= !(filter.isOnBaseResourceChildren() && context.getBaseSnapshot() == null);
-    valid &= !(filter.isOnFavourites() && context.getUserId() == null);
-    valid &= validateMeasureConditions(filter);
-    valid &= validateSort(filter);
-    return valid;
-  }
-
-  private static boolean validateMeasureConditions(MeasureFilter filter) {
-    boolean valid = true;
-    for (MeasureFilterCondition condition : filter.getMeasureConditions()) {
-      if (condition.period() != null && condition.period() < 1) {
-        valid = false;
-      }
-      if (condition.metric() == null) {
-        valid = false;
-      }
-    }
-    return valid;
-  }
-
-  private static boolean validateSort(MeasureFilter filter) {
-    boolean valid = true;
-    if (filter.sort().period() != null && filter.sort().period() < 1) {
-      valid = false;
-    }
-    if (filter.sort().onMeasures() && filter.sort().metric() == null) {
-      valid = false;
-    }
-    return valid;
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java
deleted file mode 100644 (file)
index 45e78f6..0000000
+++ /dev/null
@@ -1,195 +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.core.measure;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-public class MeasureFilterFactory implements ServerComponent {
-
-  private final MetricFinder metricFinder;
-  private final System2 system;
-
-  public MeasureFilterFactory(MetricFinder metricFinder, System2 system) {
-    this.metricFinder = metricFinder;
-    this.system = system;
-  }
-
-  public MeasureFilter create(Map<String, Object> properties) {
-    MeasureFilter filter = new MeasureFilter();
-    filter.setBaseResourceKey((String) properties.get("base"));
-    filter.setResourceScopes(toList(properties.get("scopes")));
-    filter.setResourceQualifiers(toList(properties.get("qualifiers")));
-    MeasureFilterCondition condition = alertToCondition(toList(properties.get("alertLevels")));
-    if (condition != null) {
-      filter.addCondition(condition);
-    }
-    String onBaseComponents = (String) properties.get("onBaseComponents");
-    if (onBaseComponents != null) {
-      filter.setOnBaseResourceChildren(Boolean.valueOf(onBaseComponents));
-    }
-    filter.setResourceName((String) properties.get("nameSearch"));
-    filter.setResourceKey((String) properties.get("keySearch"));
-    String onFavourites = (String) properties.get("onFavourites");
-    if (onFavourites != null) {
-      filter.setUserFavourites(Boolean.valueOf(onFavourites));
-    }
-    fillDateConditions(filter, properties);
-    fillSorting(filter, properties);
-    fillMeasureConditions(properties, filter);
-    return filter;
-  }
-
-  private void fillDateConditions(MeasureFilter filter, Map<String, Object> properties) {
-    String fromDate = (String) properties.get("fromDate");
-    if (fromDate != null) {
-      filter.setFromDate(toDate(fromDate));
-    } else {
-      filter.setFromDate(toDays((String) properties.get("ageMaxDays")));
-    }
-    String toDate = (String) properties.get("toDate");
-    if (toDate != null) {
-      filter.setToDate(toDate(toDate));
-    } else {
-      filter.setToDate(toDays((String) properties.get("ageMinDays")));
-    }
-  }
-
-  private void fillMeasureConditions(Map<String, Object> properties, MeasureFilter filter) {
-    for (int index = 1; index <= 3; index++) {
-      MeasureFilterCondition condition = toCondition(properties, index);
-      if (condition != null) {
-        filter.addCondition(condition);
-      }
-    }
-  }
-
-  private void fillSorting(MeasureFilter filter, Map<String, Object> properties) {
-    String s = (String) properties.get("sort");
-    if (s != null) {
-      if (StringUtils.startsWith(s, "metric:")) {
-        String[] fields = StringUtils.split(s, ':');
-        Metric metric = metricFinder.findByKey(fields[1]);
-        if (metric != null) {
-          filter.setSortOnMetric(metric);
-          if (fields.length == 3) {
-            filter.setSortOnPeriod(Integer.parseInt(fields[2]));
-          }
-        }
-      } else {
-        filter.setSortOn(MeasureFilterSort.Field.valueOf(s.toUpperCase()));
-      }
-    }
-
-    if (properties.containsKey("asc")) {
-      filter.setSortAsc(Boolean.valueOf((String) properties.get("asc")));
-    }
-  }
-
-  @CheckForNull
-  private MeasureFilterCondition toCondition(Map<String, Object> props, int index) {
-    MeasureFilterCondition condition = null;
-    String metricKey = (String) props.get("c" + index + "_metric");
-    String op = (String) props.get("c" + index + "_op");
-    String val = (String) props.get("c" + index + "_val");
-    if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
-      Metric metric = metricFinder.findByKey(metricKey);
-      MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
-      condition = new MeasureFilterCondition(metric, operator, Double.parseDouble(val));
-      String period = (String) props.get("c" + index + "_period");
-      if (period != null) {
-        condition.setPeriod(Integer.parseInt(period));
-      }
-    }
-    return condition;
-  }
-
-  @CheckForNull
-  private MeasureFilterCondition alertToCondition(List<String> alertLevels) {
-    if (alertLevels == null || alertLevels.isEmpty()) {
-      return null;
-    }
-    MeasureFilterCondition condition = null;
-    String metricKey = CoreMetrics.ALERT_STATUS_KEY;
-    String op = "in";
-    List<String> alertLevelsUppercase = Lists.transform(alertLevels, new Function<String, String>() {
-      @Override
-      public String apply(String input) {
-        return input != null ? input.toUpperCase() : "";
-      }
-    });
-    String val = "('" + Joiner.on("', '").join(alertLevelsUppercase) + "')";
-    if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
-      Metric metric = metricFinder.findByKey(metricKey);
-      MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
-      condition = new MeasureFilterCondition(metric, operator, val);
-    }
-    return condition;
-  }
-
-  private List<String> toList(@Nullable Object obj) {
-    List<String> result = null;
-    if (obj != null) {
-      if (obj instanceof String) {
-        result = Arrays.asList((String) obj);
-      } else {
-        result = (List<String>) obj;
-      }
-    }
-    return result;
-  }
-
-  @CheckForNull
-  private Date toDate(@Nullable String date) {
-    if (date != null) {
-      return DateUtils.parseDate(date);
-    }
-    return null;
-  }
-
-  @CheckForNull
-  private Date toDays(@Nullable String s) {
-    if (s != null) {
-      int days = Integer.valueOf(s);
-      Date date = org.apache.commons.lang.time.DateUtils.truncate(new Date(system.now()), Calendar.DATE);
-      date = org.apache.commons.lang.time.DateUtils.addDays(date, -days);
-      return date;
-    }
-    return null;
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterResult.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterResult.java
deleted file mode 100644 (file)
index f148417..0000000
+++ /dev/null
@@ -1,71 +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.core.measure;
-
-import javax.annotation.Nullable;
-
-import java.util.List;
-
-public class MeasureFilterResult {
-
-  public static enum Error {
-    UNKNOWN, VALUE_SHOULD_BE_A_NUMBER
-  }
-
-  private List<MeasureFilterRow> rows = null;
-  private Error error = null;
-
-  MeasureFilterResult() {
-  }
-
-  public List<MeasureFilterRow> getRows() {
-    return rows;
-  }
-
-  public Error getError() {
-    return error;
-  }
-
-  MeasureFilterResult setRows(@Nullable List<MeasureFilterRow> rows) {
-    this.rows = rows;
-    return this;
-  }
-
-  MeasureFilterResult setError(@Nullable Error err) {
-    this.error = err;
-    return this;
-  }
-
-  public boolean isSuccess() {
-    return error == null;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder sb = new StringBuilder();
-    if (rows != null) {
-      sb.append(rows.size()).append(" rows, ");
-    }
-    if (error != null) {
-      sb.append("error=").append(error).append(", ");
-    }
-    return sb.toString();
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterRow.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterRow.java
deleted file mode 100644 (file)
index adecb1a..0000000
+++ /dev/null
@@ -1,75 +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.core.measure;
-
-import org.apache.commons.lang.StringUtils;
-
-import java.sql.Timestamp;
-
-public class MeasureFilterRow {
-  private final long snapshotId;
-  private final long resourceId;
-  private final long resourceRootId;
-  private String sortText = null;
-  private Timestamp sortDate = null;
-  private Double sortDouble = null;
-
-  MeasureFilterRow(long snapshotId, long resourceId, long resourceRootId) {
-    this.snapshotId = snapshotId;
-    this.resourceId = resourceId;
-    this.resourceRootId = resourceRootId;
-  }
-
-  public long getSnapshotId() {
-    return snapshotId;
-  }
-
-  public long getResourceId() {
-    return resourceId;
-  }
-
-  public long getResourceRootId() {
-    return resourceRootId;
-  }
-
-  public String getSortText() {
-    return sortText;
-  }
-
-  void setSortText(String s) {
-    this.sortText = StringUtils.defaultString(s);
-  }
-
-  Timestamp getSortDate() {
-    return sortDate;
-  }
-
-  void setSortDate(Timestamp sortDate) {
-    this.sortDate = sortDate;
-  }
-
-  Double getSortDouble() {
-    return sortDouble;
-  }
-
-  void setSortDouble(Double sortDouble) {
-    this.sortDouble = sortDouble;
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java
deleted file mode 100644 (file)
index b8c09b1..0000000
+++ /dev/null
@@ -1,136 +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.core.measure;
-
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-
-class MeasureFilterSort {
-  public static enum Field {
-    KEY, NAME, VERSION, METRIC, SHORT_NAME, DESCRIPTION,
-    // Sort by last analysis date
-    DATE,
-    // Sort by project creation date
-    PROJECT_CREATION_DATE
-  }
-
-  private Field field = Field.NAME;
-  private Metric metric = null;
-  private Integer period = null;
-  private boolean asc = true;
-
-  MeasureFilterSort() {
-  }
-
-  void setField(Field field) {
-    this.field = field;
-  }
-
-  void setMetric(Metric metric) {
-    this.field = Field.METRIC;
-    this.metric = metric;
-  }
-
-  Integer period() {
-    return period;
-  }
-
-  void setPeriod(Integer period) {
-    this.period = period;
-  }
-
-  void setAsc(boolean asc) {
-    this.asc = asc;
-  }
-
-  public Field field() {
-    return field;
-  }
-
-  boolean onMeasures() {
-    return field == Field.METRIC;
-  }
-
-  Metric metric() {
-    return metric;
-  }
-
-  boolean isOnMeasure() {
-    return metric != null;
-  }
-
-  boolean isOnNumericMeasure() {
-    return metric != null && metric.isNumericType();
-  }
-
-  boolean isOnDate() {
-    return Field.DATE.equals(field) || Field.PROJECT_CREATION_DATE.equals(field);
-  }
-
-  boolean isOnAlert() {
-    return metric != null && metric.getKey().equals(CoreMetrics.ALERT_STATUS_KEY);
-  }
-
-  boolean isAsc() {
-    return asc;
-  }
-
-  String column() {
-    // only numeric metrics can be sorted by database, else results are sorted programmatically.
-    String column;
-    switch (field) {
-      case KEY:
-        column = "p.kee";
-        break;
-      case NAME:
-        column = "p.long_name";
-        break;
-      case SHORT_NAME:
-        column = "p.name";
-        break;
-      case DESCRIPTION:
-        column = "p.description";
-        break;
-      case VERSION:
-        column = "s.version";
-        break;
-      case DATE:
-        column = "s.created_at";
-        break;
-      case PROJECT_CREATION_DATE:
-        column = "p.created_at";
-        break;
-      case METRIC:
-        column = getMetricColumn();
-        break;
-      default:
-        throw new IllegalArgumentException("Unsupported sorting: " + field);
-    }
-    return column;
-  }
-
-  private String getMetricColumn(){
-    if (metric.isNumericType()) {
-      return period != null ? "pmsort.variation_value_" + period : "pmsort.value";
-    } else {
-      return "pmsort.text_value";
-    }
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSql.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSql.java
deleted file mode 100644 (file)
index 3871373..0000000
+++ /dev/null
@@ -1,361 +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.core.measure;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
-import org.apache.commons.dbutils.DbUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.core.persistence.Database;
-import org.sonar.core.persistence.dialect.MsSql;
-import org.sonar.core.persistence.dialect.Oracle;
-import org.sonar.core.resource.SnapshotDto;
-
-import javax.annotation.Nullable;
-
-import java.sql.*;
-import java.sql.Date;
-import java.util.*;
-
-class MeasureFilterSql {
-
-  private final Database database;
-  private final MeasureFilter filter;
-  private final MeasureFilterContext context;
-  private final String sql;
-  private final List<Date> dateParameters = Lists.newArrayList();
-
-  MeasureFilterSql(Database database, MeasureFilter filter, MeasureFilterContext context) {
-    this.database = database;
-    this.filter = filter;
-    this.context = context;
-    this.sql = generateSql();
-  }
-
-  List<MeasureFilterRow> execute(Connection connection) throws SQLException {
-    PreparedStatement statement = connection.prepareStatement(sql);
-    ResultSet rs = null;
-    try {
-      for (int index = 0; index < dateParameters.size(); index++) {
-        statement.setDate(index + 1, dateParameters.get(index));
-      }
-      rs = statement.executeQuery();
-      return process(rs);
-
-    } finally {
-      DbUtils.closeQuietly(rs);
-      DbUtils.closeQuietly(statement);
-    }
-  }
-
-  String sql() {
-    return sql;
-  }
-
-  private String generateSql() {
-    StringBuilder sb = new StringBuilder(1000);
-    sb.append("SELECT s.id, s.project_id, s.root_project_id, ");
-    sb.append(filter.sort().column());
-    sb.append(" FROM snapshots s INNER JOIN projects p ON s.project_id=p.id ");
-
-    for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
-      MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
-      sb.append(" INNER JOIN project_measures pmcond").append(index);
-      sb.append(" ON s.id=pmcond").append(index).append(".snapshot_id AND ");
-      condition.appendSqlCondition(sb, index);
-    }
-
-    if (filter.isOnFavourites()) {
-      sb.append(" INNER JOIN properties props ON props.resource_id=s.project_id ");
-    }
-
-    if (filter.sort().isOnMeasure()) {
-      sb.append(" LEFT OUTER JOIN project_measures pmsort ON s.id=pmsort.snapshot_id AND pmsort.metric_id=");
-      sb.append(filter.sort().metric().getId());
-      sb.append(" AND pmsort.rule_id IS NULL AND pmsort.rule_priority IS NULL AND pmsort.characteristic_id IS NULL AND pmsort.person_id IS NULL ");
-    }
-
-    sb.append(" WHERE ");
-    appendResourceConditions(sb);
-
-    for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
-      MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
-      sb.append(" AND ");
-      condition.appendSqlCondition(sb, index);
-    }
-
-    return sb.toString();
-  }
-
-  private void appendResourceConditions(StringBuilder sb) {
-    sb.append(" s.status='P' AND s.islast=").append(database.getDialect().getTrueSqlValue());
-    if (context.getBaseSnapshot() == null) {
-      sb.append(" AND p.copy_resource_id IS NULL ");
-    }
-    if (!filter.getResourceQualifiers().isEmpty()) {
-      sb.append(" AND s.qualifier IN ");
-      appendInStatement(filter.getResourceQualifiers(), sb);
-    }
-    if (!filter.getResourceScopes().isEmpty()) {
-      sb.append(" AND s.scope IN ");
-      appendInStatement(filter.getResourceScopes(), sb);
-    }
-    appendDateConditions(sb);
-    appendFavouritesCondition(sb);
-    appendResourceNameCondition(sb);
-    appendResourceKeyCondition(sb);
-    appendResourceBaseCondition(sb);
-  }
-
-  private void appendDateConditions(StringBuilder sb) {
-    java.util.Date fromDate = filter.getFromDate();
-    if (fromDate != null) {
-      sb.append(" AND s.created_at >= ? ");
-      dateParameters.add(new Date(fromDate.getTime()));
-    }
-    java.util.Date toDate = filter.getToDate();
-    if (toDate != null) {
-      sb.append(" AND s.created_at <= ? ");
-      dateParameters.add(new Date(toDate.getTime()));
-    }
-  }
-
-  private void appendFavouritesCondition(StringBuilder sb) {
-    if (filter.isOnFavourites()) {
-      sb.append(" AND props.prop_key='favourite' AND props.resource_id IS NOT NULL AND props.user_id=");
-      sb.append(context.getUserId());
-      sb.append(" ");
-    }
-  }
-
-  private void appendResourceBaseCondition(StringBuilder sb) {
-    SnapshotDto baseSnapshot = context.getBaseSnapshot();
-    if (baseSnapshot != null) {
-      if (filter.isOnBaseResourceChildren()) {
-        sb.append(" AND s.parent_snapshot_id=").append(baseSnapshot.getId());
-      } else {
-        Long rootSnapshotId = baseSnapshot.getRootId() != null ? baseSnapshot.getRootId() : baseSnapshot.getId();
-        sb.append(" AND s.root_snapshot_id=").append(rootSnapshotId);
-        sb.append(" AND s.path LIKE '").append(StringUtils.defaultString(baseSnapshot.getPath())).append(baseSnapshot.getId()).append(".%'");
-      }
-    }
-  }
-
-  private void appendResourceKeyCondition(StringBuilder sb) {
-    if (StringUtils.isNotBlank(filter.getResourceKey())) {
-      sb.append(" AND UPPER(p.kee) LIKE '%");
-      sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.upperCase(filter.getResourceKey()))));
-      sb.append("%'");
-      appendEscapeForSomeDb(sb);
-    }
-  }
-
-  private void appendResourceNameCondition(StringBuilder sb) {
-    if (StringUtils.isNotBlank(filter.getResourceName())) {
-      sb.append(" AND s.project_id IN (SELECT rindex.resource_id FROM resource_index rindex WHERE rindex.kee LIKE '");
-      sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.lowerCase(filter.getResourceName()))));
-      sb.append("%'");
-      appendEscapeForSomeDb(sb);
-      if (!filter.getResourceQualifiers().isEmpty()) {
-        sb.append(" AND rindex.qualifier IN ");
-        appendInStatement(filter.getResourceQualifiers(), sb);
-      }
-      sb.append(") ");
-    }
-  }
-
-  List<MeasureFilterRow> process(ResultSet rs) throws SQLException {
-    List<MeasureFilterRow> rows = Lists.newArrayList();
-    RowProcessor rowProcessor;
-    if (filter.sort().isOnNumericMeasure()) {
-      rowProcessor = new NumericSortRowProcessor();
-    } else if (filter.sort().isOnDate()) {
-      rowProcessor = new DateSortRowProcessor();
-    } else if (filter.sort().isOnAlert()) {
-      rowProcessor = new AlertSortRowProcessor();
-    } else {
-      rowProcessor = new TextSortRowProcessor();
-    }
-
-    while (rs.next()) {
-      rows.add(rowProcessor.fetch(rs));
-    }
-
-    return rowProcessor.sort(rows, filter.sort().isAsc());
-  }
-
-  private static void appendInStatement(List<String> values, StringBuilder to) {
-    to.append(" (");
-    for (int i = 0; i < values.size(); i++) {
-      if (i > 0) {
-        to.append(",");
-      }
-      to.append("'");
-      to.append(StringEscapeUtils.escapeSql(values.get(i)));
-      to.append("'");
-    }
-    to.append(") ");
-  }
-
-  /**
-   * Replace escape percent and underscore by adding a slash just before
-   */
-  private String escapePercentAndUnderscrore(String value){
-    return value.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_");
-  }
-
-  private void appendEscapeForSomeDb(StringBuilder sb){
-    if (database.getDialect().getId().equals(Oracle.ID) || database.getDialect().getId().equals(MsSql.ID)) {
-      sb.append(" ESCAPE '\\'");
-    }
-  }
-
-  abstract static class RowProcessor {
-    abstract Function sortFieldFunction();
-
-    abstract Ordering sortFieldOrdering(boolean ascending);
-
-    abstract MeasureFilterRow fetch(ResultSet rs) throws SQLException;
-
-    final List<MeasureFilterRow> sort(List<MeasureFilterRow> rows, boolean ascending) {
-      Ordering<MeasureFilterRow> ordering = sortFieldOrdering(ascending).onResultOf(sortFieldFunction());
-      return ordering.immutableSortedCopy(rows);
-    }
-  }
-
-  static class TextSortRowProcessor extends RowProcessor {
-    MeasureFilterRow fetch(ResultSet rs) throws SQLException {
-      MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
-      row.setSortText(rs.getString(4));
-      return row;
-    }
-
-    Function sortFieldFunction() {
-      return new Function<MeasureFilterRow, String>() {
-        public String apply(MeasureFilterRow row) {
-          return row.getSortText();
-        }
-      };
-    }
-
-    Ordering sortFieldOrdering(boolean ascending) {
-      Ordering<String> ordering = Ordering.from(String.CASE_INSENSITIVE_ORDER);
-      if (!ascending) {
-        ordering = ordering.reverse();
-      }
-      return ordering;
-    }
-  }
-
-  static class AlertSortRowProcessor extends TextSortRowProcessor {
-    Function sortFieldFunction() {
-      return new Function<MeasureFilterRow, Integer>() {
-        public Integer apply(MeasureFilterRow row) {
-          return ImmutableList.of("OK", "WARN", "ERROR").indexOf(row.getSortText());
-        }
-      };
-    }
-
-    @Override
-    Ordering sortFieldOrdering(boolean ascending) {
-      Ordering<Integer> ordering = Ordering.<Integer>natural().nullsLast();
-      if (!ascending) {
-        ordering = ordering.reverse();
-      }
-      return ordering;
-    }
-  }
-
-  static class NumericSortRowProcessor extends RowProcessor {
-    MeasureFilterRow fetch(ResultSet rs) throws SQLException {
-      MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
-      double value = rs.getDouble(4);
-      if (!rs.wasNull()) {
-        row.setSortDouble(value);
-      }
-      return row;
-    }
-
-    Function sortFieldFunction() {
-      return new Function<MeasureFilterRow, Double>() {
-        public Double apply(MeasureFilterRow row) {
-          return row.getSortDouble();
-        }
-      };
-    }
-
-    Ordering sortFieldOrdering(boolean ascending) {
-      return ascending ? Ordering.natural().nullsLast() : Ordering.natural().reverse().nullsLast();
-    }
-  }
-
-  static class DateSortRowProcessor extends RowProcessor {
-    MeasureFilterRow fetch(ResultSet rs) throws SQLException {
-      MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
-      row.setSortDate(rs.getTimestamp(4));
-      return row;
-    }
-
-    Function sortFieldFunction() {
-      return new Function<MeasureFilterRow, Timestamp>() {
-        public Timestamp apply(MeasureFilterRow row) {
-          return row.getSortDate();
-        }
-      };
-    }
-
-    Ordering sortFieldOrdering(boolean ascending) {
-      return newObjectOrdering(ascending);
-    }
-  }
-
-  private static Ordering newObjectOrdering(boolean ascending) {
-    if (ascending) {
-      return Ordering.from(new Comparator<Comparable>() {
-        public int compare(@Nullable Comparable left, @Nullable Comparable right) {
-          if (left == null) {
-            return 1;
-          }
-          if (right == null) {
-            return -1;
-          }
-
-          return left.compareTo(right);
-        }
-      });
-    }
-    return Ordering.from(new Comparator<Comparable>() {
-      public int compare(@Nullable Comparable left, @Nullable Comparable right) {
-        if (left == null) {
-          return 1;
-        }
-        if (right == null) {
-          return -1;
-        }
-
-        return -left.compareTo(right);
-      }
-    });
-  }
-}
-
index b45c9ac4bd0ab12aad038533c2d4c84b76f43df0..771c8134ef6223fcd16d1727998cd9762f77e7ec 100644 (file)
@@ -24,9 +24,14 @@ import org.sonar.core.dashboard.ActiveDashboardDao;
 import org.sonar.core.dashboard.DashboardDao;
 import org.sonar.core.duplication.DuplicationDao;
 import org.sonar.core.graph.jdbc.GraphDao;
-import org.sonar.core.issue.db.*;
+import org.sonar.core.issue.db.ActionPlanDao;
+import org.sonar.core.issue.db.ActionPlanStatsDao;
+import org.sonar.core.issue.db.IssueChangeDao;
+import org.sonar.core.issue.db.IssueDao;
+import org.sonar.core.issue.db.IssueFilterDao;
+import org.sonar.core.issue.db.IssueFilterFavouriteDao;
+import org.sonar.core.issue.db.IssueStatsDao;
 import org.sonar.core.measure.db.MeasureDao;
-import org.sonar.core.measure.db.MeasureFilterDao;
 import org.sonar.core.notification.db.NotificationQueueDao;
 import org.sonar.core.permission.PermissionDao;
 import org.sonar.core.permission.PermissionTemplateDao;
@@ -43,13 +48,18 @@ import org.sonar.core.source.db.SnapshotSourceDao;
 import org.sonar.core.technicaldebt.db.CharacteristicDao;
 import org.sonar.core.technicaldebt.db.RequirementDao;
 import org.sonar.core.template.LoadedTemplateDao;
-import org.sonar.core.user.*;
+import org.sonar.core.user.AuthorDao;
+import org.sonar.core.user.AuthorizationDao;
+import org.sonar.core.user.GroupMembershipDao;
+import org.sonar.core.user.RoleDao;
+import org.sonar.core.user.UserDao;
 
 import java.util.List;
 
 public final class DaoUtils {
 
   private DaoUtils() {
+    // only static stuff
   }
 
   @SuppressWarnings("unchecked")
@@ -72,7 +82,6 @@ public final class DaoUtils {
       IssueFilterFavouriteDao.class,
       LoadedTemplateDao.class,
       MeasureDao.class,
-      MeasureFilterDao.class,
       NotificationQueueDao.class,
       PermissionDao.class,
       PermissionTemplateDao.class,
diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterConditionTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterConditionTest.java
deleted file mode 100644 (file)
index 81ff9f3..0000000
+++ /dev/null
@@ -1,99 +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.core.measure;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.measures.Metric;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterConditionTest {
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  @Test
-  public void create_operator_from_code() {
-    assertThat(MeasureFilterCondition.Operator.fromCode("eq")).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
-    assertThat(MeasureFilterCondition.Operator.fromCode("lte")).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
-  }
-
-  @Test
-  public void fail_if_operator_code_not_found() {
-    thrown.expect(IllegalArgumentException.class);
-    MeasureFilterCondition.Operator.fromCode("xxx");
-  }
-
-  @Test
-  public void operator_sql() {
-    assertThat(MeasureFilterCondition.Operator.EQUALS.getSql()).isEqualTo("=");
-    assertThat(MeasureFilterCondition.Operator.LESS_OR_EQUALS.getSql()).isEqualTo("<=");
-    assertThat(MeasureFilterCondition.Operator.GREATER.getSql()).isEqualTo(">");
-  }
-
-  @Test
-  public void value_condition() {
-    Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
-    ncloc.setId(123);
-    MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.GREATER, 10.0);
-
-    assertThat(condition.metric()).isEqualTo(ncloc);
-    assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER);
-    assertThat(condition.period()).isNull();
-    assertThat(condition.value()).isEqualTo(10.0);
-    assertThat(condition.textValue()).isNull();
-    assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.value");
-    assertThat(condition.toString()).isNotEmpty();
-    assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.value > 10.0 AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
-  }
-
-  @Test
-  public void variation_condition() {
-    Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
-    ncloc.setId(123);
-    MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 10.0);
-    condition.setPeriod(3);
-
-    assertThat(condition.metric()).isEqualTo(ncloc);
-    assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
-    assertThat(condition.period()).isEqualTo(3);
-    assertThat(condition.value()).isEqualTo(10.0);
-    assertThat(condition.appendSqlColumn(new StringBuilder(), 2).toString()).isEqualTo("pmcond2.variation_value_3");
-    assertThat(condition.toString()).isNotEmpty();
-    assertThat(condition.appendSqlCondition(new StringBuilder(), 2).toString()).isEqualTo(" pmcond2.metric_id=123 AND pmcond2.variation_value_3 <= 10.0 AND pmcond2.rule_id IS NULL AND pmcond2.rule_priority IS NULL AND pmcond2.characteristic_id IS NULL AND pmcond2.person_id IS NULL ");
-  }
-
-  @Test
-  public void text_value_condition() {
-    Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
-    ncloc.setId(123);
-    MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.EQUALS, "\"foo\"");
-
-    assertThat(condition.metric()).isEqualTo(ncloc);
-    assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
-    assertThat(condition.period()).isNull();
-    assertThat(condition.value()).isEqualTo(0);
-    assertThat(condition.textValue()).isEqualTo("\"foo\"");
-    assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.text_value");
-    assertThat(condition.toString()).isNotEmpty();
-    assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.text_value = \"foo\" AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterContextTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterContextTest.java
deleted file mode 100644 (file)
index 4f13654..0000000
+++ /dev/null
@@ -1,44 +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.core.measure;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Test;
-
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterContextTest {
-  @Test
-  public void test_empty_toString() {
-    MeasureFilterContext context = new MeasureFilterContext();
-    assertThat(context.toString()).isNotEmpty();
-  }
-
-  @Test
-  public void test_toString() {
-    MeasureFilterContext context = new MeasureFilterContext();
-    context.setData("{qualifiers=TRK}");
-    context.setSql("SELECT *");
-    context.setUserId(50L);
-    assertThat(context.toString()).isEqualTo("MeasureFilterContext[filter={qualifiers=TRK},sql=SELECT *,user=50]");
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterEngineTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterEngineTest.java
deleted file mode 100644 (file)
index b3b258a..0000000
+++ /dev/null
@@ -1,77 +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.core.measure;
-
-import com.google.common.collect.ImmutableMap;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.core.profiling.Profiling;
-
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class MeasureFilterEngineTest {
-
-  @Test
-  public void should_create_and_execute_filter() throws Exception {
-    Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
-    MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
-    MeasureFilter filter = new MeasureFilter();
-    when(factory.create(filterMap)).thenReturn(filter);
-    MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
-
-    MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
-
-    final long userId = 50L;
-    engine.execute(filterMap, userId);
-    verify(executor).execute(refEq(filter), argThat(new BaseMatcher<MeasureFilterContext>() {
-      public boolean matches(Object o) {
-        MeasureFilterContext context = (MeasureFilterContext) o;
-        return "{qualifiers=TRK}".equals(context.getData()) && context.getUserId() == userId;
-      }
-
-      public void describeTo(Description description) {
-      }
-    }));
-  }
-
-  @Test
-  public void keep_error_but_do_not_fail() throws Exception {
-    Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
-    MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
-    when(factory.create(filterMap)).thenThrow(new IllegalArgumentException());
-    MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
-
-    MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
-    MeasureFilterResult result = engine.execute(filterMap, 50L);
-
-    assertThat(result.isSuccess()).isFalse();
-    assertThat(result.getError()).isEqualTo(MeasureFilterResult.Error.UNKNOWN);
-    assertThat(result.getRows()).isNull();
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterExecutorTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterExecutorTest.java
deleted file mode 100644 (file)
index 97783f5..0000000
+++ /dev/null
@@ -1,611 +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.core.measure;
-
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.persistence.TestDatabase;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.SnapshotDto;
-
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterExecutorTest {
-  private static final long JAVA_PROJECT_ID = 1L;
-  private static final long JAVA_FILE_BIG_ID = 3L;
-  private static final long JAVA_FILE_TINY_ID = 4L;
-  private static final long JAVA_PROJECT_SNAPSHOT_ID = 101L;
-  private static final long JAVA_FILE_BIG_SNAPSHOT_ID = 103L;
-  private static final long JAVA_FILE_TINY_SNAPSHOT_ID = 104L;
-  private static final long JAVA_PACKAGE_SNAPSHOT_ID = 102L;
-  private static final long PHP_PROJECT_ID = 10L;
-  private static final long PHP_SNAPSHOT_ID = 110L;
-  private static final Metric METRIC_LINES = new Metric.Builder("lines", "Lines", Metric.ValueType.INT).create().setId(1);
-  private static final Metric METRIC_PROFILE = new Metric.Builder("profile", "Profile", Metric.ValueType.STRING).create().setId(2);
-  private static final Metric METRIC_COVERAGE = new Metric.Builder("coverage", "Coverage", Metric.ValueType.FLOAT).create().setId(3);
-  private static final Metric METRIC_UNKNOWN = new Metric.Builder("unknown", "Unknown", Metric.ValueType.FLOAT).create().setId(4);
-
-  private MeasureFilterExecutor executor;
-
-  @ClassRule
-  public static TestDatabase db = new TestDatabase();
-
-  @Before
-  public void before() {
-    executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis()));
-  }
-
-  @Test
-  public void should_return_empty_results_if_empty_filter() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter();
-    assertThat(filter.isEmpty()).isTrue();
-
-    assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
-  }
-
-  @Test
-  public void invalid_filter_should_not_return_results() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setUserFavourites(true);
-    // anonymous user does not have favourites
-    assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
-  }
-
-  @Test
-  public void filter_is_not_valid_if_missing_base_snapshot() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilterContext context = new MeasureFilterContext();
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setOnBaseResourceChildren(true);
-    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
-
-    context.setBaseSnapshot(new SnapshotDto().setId(123L));
-    assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
-  }
-
-  @Test
-  public void filter_is_not_valid_if_condition_on_unknown_metric() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilterContext context = new MeasureFilterContext();
-    MeasureFilter filter = new MeasureFilter().addCondition(new MeasureFilterCondition(null, MeasureFilterCondition.Operator.LESS, 3.0));
-    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
-  }
-
-  @Test
-  public void filter_is_not_valid_if_sorting_on_unknown_metric() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilterContext context = new MeasureFilterContext();
-    MeasureFilter filter = new MeasureFilter().setSortOnMetric(null);
-    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
-  }
-
-  @Test
-  public void filter_is_not_valid_if_anonymous_favourites() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilterContext context = new MeasureFilterContext();
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setUserFavourites(true);
-    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
-
-    context.setUserId(123L);
-    assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
-  }
-
-  @Test
-  public void projects_without_measure_conditions() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);
-    verifyJavaProject(rows.get(0));
-    verifyPhpProject(rows.get(1));
-  }
-
-  @Test
-  public void should_prevent_sql_injection_through_parameters() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter()
-      .setResourceQualifiers(Arrays.asList("'"))
-      .setBaseResourceKey("'")
-      .setResourceKey("'")
-      .setResourceName("'")
-      .setResourceName("'")
-      .setResourceScopes(Arrays.asList("'"));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-    // an exception would be thrown if SQL is not valid
-    assertThat(rows).isEmpty();
-  }
-
-  @Test
-  public void test_default_sort() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"));
-
-    assertThat(filter.sort().isAsc()).isTrue();
-    assertThat(filter.sort().field()).isEqualTo(MeasureFilterSort.Field.NAME);
-    assertThat(filter.sort().metric()).isNull();
-  }
-
-  @Test
-  public void sort_by_ascending_resource_name() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Big -> Tiny
-    assertThat(rows).hasSize(2);
-    verifyJavaBigFile(rows.get(0));
-    verifyJavaTinyFile(rows.get(1));
-  }
-
-  @Test
-  public void sort_by_ascending_resource_key() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.KEY);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Big -> Tiny
-    assertThat(rows).hasSize(2);
-    verifyJavaBigFile(rows.get(0));
-    verifyJavaTinyFile(rows.get(1));
-  }
-
-  @Test
-  public void sort_by_ascending_resource_version() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.VERSION);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Java Project 1.0 then Php Project 3.0
-    assertThat(rows).hasSize(2);
-    verifyJavaProject(rows.get(0));
-    verifyPhpProject(rows.get(1));
-  }
-
-  @Test
-  public void sort_by_descending_resource_name() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Tiny -> Big
-    assertThat(rows).hasSize(2);
-    verifyJavaTinyFile(rows.get(0));
-    verifyJavaBigFile(rows.get(1));
-  }
-
-  @Test
-  public void sort_by_ascending_text_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);
-    verifyPhpProject(rows.get(0));//php way
-    verifyJavaProject(rows.get(1));// Sonar way
-  }
-
-  @Test
-  public void sort_by_descending_text_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);
-    verifyJavaProject(rows.get(0));// Sonar way
-    verifyPhpProject(rows.get(1));//php way
-  }
-
-  @Test
-  public void sort_by_missing_text_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    // the metric 'profile' is not set on files
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_PROFILE);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);//2 files randomly sorted
-  }
-
-  @Test
-  public void sort_by_ascending_numeric_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Tiny -> Big
-    assertThat(rows).hasSize(2);
-    verifyJavaTinyFile(rows.get(0));
-    verifyJavaBigFile(rows.get(1));
-  }
-
-  @Test
-  public void sort_by_descending_numeric_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Big -> Tiny
-    assertThat(rows).hasSize(2);
-    verifyJavaBigFile(rows.get(0));
-    verifyJavaTinyFile(rows.get(1));
-  }
-
-  @Test
-  public void null_measures_are_ordered_after_descending_numeric_measures() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
-      .setSortOnMetric(METRIC_COVERAGE).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Java project has coverage but not PHP
-    assertThat(rows).hasSize(2);
-    verifyJavaProject(rows.get(0));
-    verifyPhpProject(rows.get(1));
-  }
-
-  @Test
-  public void null_measures_are_ordered_after_ascending_numeric_measures() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
-      .setSortOnMetric(METRIC_COVERAGE).setSortAsc(true);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Java project has coverage but not PHP
-    assertThat(rows).hasSize(2);
-    verifyJavaProject(rows.get(0));
-    verifyPhpProject(rows.get(1));
-  }
-
-  @Test
-  public void sort_by_missing_numeric_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    // coverage measures are not computed
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_UNKNOWN);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // 2 files, random order
-    assertThat(rows).hasSize(2);
-  }
-
-  @Test
-  public void sort_by_ascending_variation() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_LINES).setSortOnPeriod(5);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);
-    verifyJavaProject(rows.get(0));// +400
-    verifyPhpProject(rows.get(1));// +4900
-  }
-
-  @Test
-  public void sort_by_descending_variation() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
-      .setSortOnMetric(METRIC_LINES).setSortOnPeriod(5).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);
-    verifyPhpProject(rows.get(0));// +4900
-    verifyJavaProject(rows.get(1));// +400
-  }
-
-  @Test
-  public void sort_by_ascending_date() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    verifyJavaProject(rows.get(0));// 2008
-    verifyPhpProject(rows.get(1));// 2012
-  }
-
-  @Test
-  public void sort_by_descending_date() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    verifyPhpProject(rows.get(0));// 2012
-    verifyJavaProject(rows.get(1));// 2008
-  }
-
-  @Test
-  public void sort_by_ascending_created_at() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    verifyJavaProject(rows.get(0));// 2008
-    assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2008-12-19");
-    verifyPhpProject(rows.get(1));// 2012
-    assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2012-12-12");
-  }
-
-  @Test
-  public void sort_by_descending_created_at() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    verifyPhpProject(rows.get(0));// 2012
-    assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2012-12-12");
-    verifyJavaProject(rows.get(1));// 2008
-    assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2008-12-19");
-  }
-
-  @Test
-  public void sort_by_ascending_alert() throws SQLException {
-    db.prepareDbUnit(getClass(), "sort_by_alert.xml");
-
-    Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Php Project OK, Java Project WARN then Js Project ERROR
-    assertThat(rows).hasSize(3);
-    verifyPhpProject(rows.get(0));
-    verifyJavaProject(rows.get(1));
-    verifyProject(rows.get(2), 120L, 20L, 20L);
-  }
-
-  @Test
-  public void sort_by_descending_alert() throws SQLException {
-    db.prepareDbUnit(getClass(), "sort_by_alert.xml");
-
-    Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert).setSortAsc(false);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // Js Project ERROR, Java Project WARN, then Php Project OK
-    assertThat(rows).hasSize(3);
-    verifyProject(rows.get(0), 120L, 20L, 20L);
-    verifyJavaProject(rows.get(1));
-    verifyPhpProject(rows.get(2));
-  }
-
-  @Test
-  public void condition_on_numeric_measure() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
-      .setSortOnMetric(METRIC_LINES)
-      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 200));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);
-    verifyJavaBigFile(rows.get(0));
-  }
-
-  @Test
-  public void condition_on_measure_variation() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
-      .setSortOnMetric(METRIC_LINES)
-      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 1000).setPeriod(5));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);
-    verifyPhpProject(rows.get(0));
-  }
-
-  @Test
-  public void multiple_conditions_on_numeric_measures() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
-      .setSortOnMetric(METRIC_LINES)
-      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 2))
-      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 50));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);
-    verifyJavaTinyFile(rows.get(0));
-  }
-
-  @Test
-  public void filter_by_min_date() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setFromDate(DateUtils.parseDate("2012-12-13"));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
-    assertThat(rows).hasSize(1);
-    verifyPhpProject(rows.get(0));
-  }
-
-  @Test
-  public void filter_by_range_of_dates() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
-      .setFromDate(DateUtils.parseDate("2007-01-01"))
-      .setToDate(DateUtils.parseDate("2010-01-01"));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
-    assertThat(rows).hasSize(1);
-    verifyJavaProject(rows.get(0));
-  }
-
-  @Test
-  public void filter_by_component_name() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceName("PHP Proj");
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);
-    verifyPhpProject(rows.get(0));
-  }
-
-  @Test
-  public void filter_by_component_key() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceKey("Va_proje");
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);
-    verifyJavaProject(rows.get(0));
-  }
-
-  /**
-   * see SONAR-4195
-   */
-  @Test
-  public void filter_by_upper_case_component_key() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setResourceKey("big");
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);
-    verifyJavaBigFile(rows.get(0));
-  }
-
-  /**
-   * see SONAR-4796
-   */
-  @Test
-  public void escape_percent_and_underscore_when_filter_by_component_name_or_key() throws SQLException {
-    db.prepareDbUnit(getClass(), "escape_percent_and_underscore_when_filter_by_component_name_or_key.xml");
-
-    assertThat(executor.execute(
-      new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceKey("java_"),
-      new MeasureFilterContext())).hasSize(2);
-
-    assertThat(executor.execute(
-      new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceName("java%"),
-      new MeasureFilterContext())).hasSize(2);
-  }
-
-  @Test
-  public void filter_by_base_resource() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setBaseResourceKey("java_project");
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(2);
-    // default sort is on resource name
-    verifyJavaBigFile(rows.get(0));
-    verifyJavaTinyFile(rows.get(1));
-  }
-
-  @Test
-  public void filter_by_parent_resource() throws SQLException {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setBaseResourceKey("java_project").setOnBaseResourceChildren(true);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).hasSize(1);// the package org.sonar.foo
-    assertThat(rows.get(0).getSnapshotId()).isEqualTo(JAVA_PACKAGE_SNAPSHOT_ID);
-  }
-
-  @Test
-  public void filter_by_parent_without_children() throws Exception {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "PAC", "CLA")).setBaseResourceKey("java_project:org.sonar.foo.Big").setOnBaseResourceChildren(true);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
-
-    assertThat(rows).isEmpty();
-  }
-
-  @Test
-  public void filter_by_user_favourites() throws Exception {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "FIL")).setUserFavourites(true);
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
-    assertThat(rows).hasSize(2);
-    verifyJavaBigFile(rows.get(0));
-    verifyPhpProject(rows.get(1));
-  }
-
-  @Test
-  public void ignore_person_measures_in_condition() throws Exception {
-    db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
-      new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
-    );
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
-    assertThat(rows).hasSize(1);
-    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
-  }
-
-  @Test
-  public void ignore_person_measures_in_sort() throws Exception {
-    db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
-    assertThat(rows).hasSize(1);
-    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
-  }
-
-  @Test
-  public void ignore_quality_model_measures_in_condition() throws Exception {
-    db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
-      new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
-    );
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
-    assertThat(rows).hasSize(1);
-    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
-  }
-
-  @Test
-  public void ignore_quality_model_measures_in_sort() throws Exception {
-    db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
-    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
-    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
-
-    assertThat(rows).hasSize(1);
-    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
-  }
-
-
-  private void verifyJavaProject(MeasureFilterRow row) {
-    verifyProject(row, JAVA_PROJECT_SNAPSHOT_ID, JAVA_PROJECT_ID, JAVA_PROJECT_ID);
-  }
-
-  private void verifyJavaBigFile(MeasureFilterRow row) {
-    verifyProject(row, JAVA_FILE_BIG_SNAPSHOT_ID, JAVA_FILE_BIG_ID, JAVA_PROJECT_ID);
-  }
-
-  private void verifyJavaTinyFile(MeasureFilterRow row) {
-    verifyProject(row, JAVA_FILE_TINY_SNAPSHOT_ID, JAVA_FILE_TINY_ID, JAVA_PROJECT_ID);
-  }
-
-  private void verifyPhpProject(MeasureFilterRow row) {
-    verifyProject(row, PHP_SNAPSHOT_ID, PHP_PROJECT_ID, PHP_PROJECT_ID);
-  }
-
-  private void verifyProject(MeasureFilterRow row, Long snashotId, Long resourceId, Long resourceRootId) {
-    assertThat(row.getSnapshotId()).isEqualTo(snashotId);
-    assertThat(row.getResourceId()).isEqualTo(resourceId);
-    assertThat(row.getResourceRootId()).isEqualTo(resourceRootId);
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java
deleted file mode 100644 (file)
index 40ea7b6..0000000
+++ /dev/null
@@ -1,221 +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.core.measure;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class MeasureFilterFactoryTest {
-
-  System2 system = mock(System2.class);
-
-  @Test
-  public void sort_on_measure_value() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc");
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(filter.sort().column()).isEqualTo("pmsort.value");
-    assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
-    assertThat(filter.sort().period()).isNull();
-  }
-
-  @Test
-  public void sort_on_measure_variation() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc:3");
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(filter.sort().column()).isEqualTo("pmsort.variation_value_3");
-    assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
-    assertThat(filter.sort().period()).isEqualTo(3);
-  }
-
-  @Test
-  public void sort_on_name() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "name");
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(filter.sort().column()).isEqualTo("p.long_name");
-    assertThat(filter.sort().metric()).isNull();
-    assertThat(filter.sort().period()).isNull();
-  }
-
-  @Test
-  public void fallback_on_name_sort_when_metric_is_unknown() {
-    MetricFinder finder = mock(MetricFinder.class);
-    when(finder.findByKey(anyString())).thenReturn(null);
-    MeasureFilterFactory factory = new MeasureFilterFactory(finder, system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:sqale_index");
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(filter.sort().column()).isEqualTo("p.long_name");
-    assertThat(filter.sort().metric()).isNull();
-    assertThat(filter.sort().period()).isNull();
-    assertThat(filter.sort().isAsc()).isTrue();
-  }
-
-  @Test
-  public void descending_sort() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of("asc", "false");
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(filter.sort().column()).isEqualTo("p.long_name");
-    assertThat(filter.sort().metric()).isNull();
-    assertThat(filter.sort().period()).isNull();
-    assertThat(filter.sort().isAsc()).isFalse();
-  }
-
-  @Test
-  public void ascending_sort_by_default() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = Maps.newHashMap();
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(filter.sort().column()).isEqualTo("p.long_name");
-    assertThat(filter.sort().metric()).isNull();
-    assertThat(filter.sort().period()).isNull();
-    assertThat(filter.sort().isAsc()).isTrue();
-  }
-
-  @Test
-  public void date_conditions() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of(
-      "fromDate", "2012-01-25",
-      "toDate", "2012-02-18"
-    );
-    MeasureFilter filter = factory.create(props);
-
-    assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2012-01-25");
-    assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2012-02-18");
-  }
-
-  @Test
-  public void age_conditions() {
-    long today = DateUtils.parseDateTime("2013-05-18T11:00:00+0000").getTime();
-    when(system.now()).thenReturn(today);
-
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of(
-      "ageMaxDays", "3",
-      "ageMinDays", "1"
-    );
-    MeasureFilter filter = factory.create(props);
-    assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2013-05-15");
-    assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2013-05-17");
-  }
-
-  @Test
-  public void measure_value_condition() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of(
-      "c1_metric", "complexity",
-      "c1_op", "gte",
-      "c1_val", "3.14"
-    );
-    MeasureFilter filter = factory.create(props);
-
-    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
-    assertThat(conditions).hasSize(1);
-    assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
-    assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
-    assertThat(conditions.get(0).value()).isEqualTo(3.14);
-    assertThat(conditions.get(0).period()).isNull();
-  }
-
-  @Test
-  public void measure_variation_condition() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of(
-      "c1_metric", "complexity",
-      "c1_op", "gte",
-      "c1_val", "3.14",
-      "c1_period", "3"
-    );
-    MeasureFilter filter = factory.create(props);
-
-    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
-    assertThat(conditions).hasSize(1);
-    assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
-    assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
-    assertThat(conditions.get(0).value()).isEqualTo(3.14);
-    assertThat(conditions.get(0).period()).isEqualTo(3);
-  }
-
-  @Test
-  public void alert_level_condition() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of(
-      "alertLevels", Arrays.asList("error", "warn")
-    );
-    MeasureFilter filter = factory.create(props);
-
-    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
-    assertThat(conditions).hasSize(1);
-    assertThat(conditions.get(0).metric().getKey()).isEqualTo("alert_status");
-    assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.IN);
-    assertThat(conditions.get(0).value()).isEqualTo(0);
-    assertThat(conditions.get(0).textValue()).isEqualTo("('ERROR', 'WARN')");
-    assertThat(conditions.get(0).period()).isNull();
-  }
-
-  @Test
-  public void ignore_partial_measure_condition() {
-    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
-    Map<String, Object> props = ImmutableMap.<String, Object>of(
-      "c1_op", "gte",
-      "c1_val", "3.14"
-    );
-    MeasureFilter filter = factory.create(props);
-
-    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
-    assertThat(conditions).isEmpty();
-  }
-
-  private MetricFinder newMetricFinder() {
-    MetricFinder finder = mock(MetricFinder.class);
-    when(finder.findByKey(anyString())).thenAnswer(new Answer<Metric>() {
-      public Metric answer(InvocationOnMock invocationOnMock) throws Throwable {
-        String key = (String) invocationOnMock.getArguments()[0];
-        return new Metric.Builder(key, key, Metric.ValueType.INT).create();
-      }
-    });
-    return finder;
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterTest.java
deleted file mode 100644 (file)
index c50ed42..0000000
+++ /dev/null
@@ -1,65 +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.core.measure;
-
-import com.google.common.collect.Lists;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class MeasureFilterTest {
-  @Test
-  public void should_sanitize_list() {
-    assertThat(MeasureFilter.sanitize(null)).isEmpty();
-    assertThat(MeasureFilter.sanitize(Lists.<String>newArrayList())).isEmpty();
-    assertThat(MeasureFilter.sanitize(Arrays.asList(""))).isEmpty();
-    assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK"))).containsExactly("TRK");
-    assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK", "BRC"))).containsExactly("TRK", "BRC");
-  }
-
-  @Test
-  public void filter_is_not_empty_if_at_least_condition_on_favourites() {
-    assertThat(new MeasureFilter().isEmpty()).isTrue();
-    assertThat(new MeasureFilter().setUserFavourites(true).isEmpty()).isFalse();
-  }
-
-  @Test
-  public void filter_is_not_empty_if_at_least_condition_on_qualifiers() {
-    assertThat(new MeasureFilter().isEmpty()).isTrue();
-    assertThat(new MeasureFilter().setResourceQualifiers(Collections.<String>emptyList()).isEmpty()).isTrue();
-    assertThat(new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).isEmpty()).isFalse();
-  }
-
-  @Test
-  public void filter_is_not_empty_if_at_least_condition_on_scopes() {
-    assertThat(new MeasureFilter().isEmpty()).isTrue();
-    assertThat(new MeasureFilter().setResourceScopes(Collections.<String>emptyList()).isEmpty()).isTrue();
-    assertThat(new MeasureFilter().setResourceScopes(Arrays.asList("PRJ")).isEmpty()).isFalse();
-  }
-
-  @Test
-  public void filter_is_not_empty_if_at_least_condition_on_root_resource() {
-    assertThat(new MeasureFilter().isEmpty()).isTrue();
-    assertThat(new MeasureFilter().setBaseResourceKey("foo").isEmpty()).isFalse();
-  }
-}
diff --git a/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/escape_percent_and_underscore_when_filter_by_component_name_or_key.xml b/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/escape_percent_and_underscore_when_filter_by_component_name_or_key.xml
deleted file mode 100644 (file)
index 2419fb9..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<dataset>
-
-  <!-- java project -->
-  <projects kee="java_project:org.sonar.bar" long_name="org.sonar.bar" scope="FIL" qualifier="CLA" name="org.sonar.bar"
-            id="1" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <projects kee="java_project:org.sonar.foo" scope="FIL" qualifier="CLA" long_name="org.sonar.foo" name="org.sonar.foo"
-            id="2" root_id="1"
-            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <projects kee="java project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
-            name="Big"
-            id="3" root_id="1"
-            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <projects kee="java project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
-            id="4" root_id="1"
-            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="FIL" qualifier="CLA" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
-             scope="FIL" qualifier="CLA" path="101." depth="1"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
-             scope="FIL" qualifier="CLA" path="101.102." depth="2"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
-             scope="FIL" qualifier="CLA" path="101.102." depth="2"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <resource_index id="1" kee="java class1" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="CLA"/>
-  <resource_index id="2" kee="java class2" position="1" name_size="12" resource_id="2" root_project_id="1" qualifier="CLA"/>
-  <resource_index id="3" kee="java%class3" position="2" name_size="12" resource_id="3" root_project_id="1" qualifier="CLA"/>
-  <resource_index id="4" kee="java%class4" position="3" name_size="12" resource_id="4" root_project_id="1" qualifier="CLA"/>
-
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/ignore_person_measures.xml b/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/ignore_person_measures.xml
deleted file mode 100644 (file)
index c868a8d..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<dataset>
-  <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
-           short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
-           optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
-           delete_historical_data="[null]"/>
-
-  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
-            id="1" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
-
-  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-
-  <!-- standard measure -->
-  <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" person_id="[null]"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <!-- details of the measure by person -->
-  <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" person_id="30000"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" person_id="40000"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/ignore_quality_model_measures.xml b/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/ignore_quality_model_measures.xml
deleted file mode 100644 (file)
index 6289fa9..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<dataset>
-  <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
-           short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
-           optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
-           delete_historical_data="[null]"/>
-
-  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
-            id="1" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
-
-  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-
-  <!-- standard measure -->
-  <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" characteristic_id="[null]"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" person_id="[null]"/>
-
-  <!-- details of the measure by model characteristic -->
-  <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" characteristic_id="30000"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" person_id="[null]"/>
-
-  <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" characteristic_id="40000"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" person_id="[null]"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/shared.xml b/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/shared.xml
deleted file mode 100644 (file)
index 173b39e..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-<dataset>
-  <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
-           short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
-           optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
-           delete_historical_data="[null]"/>
-
-  <metrics id="2" name="profile" val_type="STRING" description="Profile" domain="Rules"
-           short_name="Profile" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV"
-           worst_value="[null]"
-           optimized_best_value="[null]" best_value="[null]" direction="0" hidden="[false]"
-           delete_historical_data="[null]"/>
-
-  <metrics id="3" name="coverage" val_type="FLOAT" description="Coverage" domain="Test"
-           short_name="Coverage" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
-           worst_value="[null]"
-           optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
-           delete_historical_data="[null]"/>
-
-  <metrics id="4" name="unknown" val_type="FLOAT" description="Coverage" domain="Test"
-             short_name="Unknown" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
-             worst_value="[null]"
-             optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
-             delete_historical_data="[null]"/>
-
-  <!-- java project -->
-  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
-            id="1" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <projects kee="java_project:org.sonar.foo" scope="DIR" qualifier="PAC" long_name="org.sonar.foo" name="org.sonar.foo"
-            id="2" root_id="1"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <projects kee="java_project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
-            name="Big"
-            id="3" root_id="1"
-            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <projects kee="java_project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
-            id="4" root_id="1"
-            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
-             scope="DIR" qualifier="PAC" path="101." depth="1"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
-             scope="FIL" qualifier="CLA" path="101.102." depth="2"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-  <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
-             scope="FIL" qualifier="CLA" path="101.102." depth="2"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-
-  <!-- lines, variation during period 5 -->
-  <project_measures id="1001" metric_id="1" value="510" snapshot_id="101"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <project_measures id="1002" metric_id="1" value="510" snapshot_id="102"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <project_measures id="1003" metric_id="1" value="500" snapshot_id="103"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <project_measures id="1004" metric_id="1" value="10" snapshot_id="104"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <!-- profile of java project -->
-  <project_measures id="1005" metric_id="2" value="[null]" snapshot_id="101"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <!-- coverage of java project -->
-  <project_measures id="1006" metric_id="3" value="12.3" snapshot_id="101"
-                      url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                      variation_value_4="[null]" variation_value_5="[null]"
-                      rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                      RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
-                      alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <!-- php project -->
-  <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
-            id="10" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2012-12-12 04:06:00.00"/>
-
-
-  <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
-             version="3.0" status="P" islast="[true]"/>
-
-  <!-- lines, many new lines during period 5 -->
-  <project_measures id="1010" metric_id="1" value="5000" snapshot_id="110"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="4900"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <project_measures id="1011" metric_id="2" value="[null]" snapshot_id="110"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="php way" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-
-  <resource_index id="1" kee="java project" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
-  <resource_index id="2" kee="java projec" position="1" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
-  <resource_index id="3" kee="java proje" position="2" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
-  <resource_index id="4" kee="java proj" position="3" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
-  <!-- etc -->
-  <resource_index id="5" kee="php project" position="0" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
-  <resource_index id="6" kee="php projec" position="1" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
-  <resource_index id="7" kee="php proje" position="2" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
-  <resource_index id="8" kee="php proj" position="3" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
-  <!-- etc -->
-
-
-  <!-- two favourites : Big.java and PHP project -->
-  <properties id="1" prop_key="favourite" resource_id="3" text_value="[null]" user_id="50"/>
-  <properties id="2" prop_key="favourite" resource_id="10" text_value="[null]" user_id="50"/>
-
-  <!-- another properties -->
-  <properties id="3" prop_key="favourite" resource_id="1" text_value="[null]" user_id="1234"/>
-  <properties id="4" prop_key="sonar.profile" resource_id="1" text_value="Sonar way" user_id="[null]"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/sort_by_alert.xml b/sonar-core/src/test/resources/org/sonar/core/measure/MeasureFilterExecutorTest/sort_by_alert.xml
deleted file mode 100644 (file)
index a837664..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<dataset>
-  <metrics id="5" name="alert_status" val_type="LEVEL" description="Alert" domain="General"
-           short_name="Alert" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
-           worst_value="[null]"
-           optimized_best_value="[true]" best_value="[null]" direction="1" hidden="[false]"
-           delete_historical_data="[null]"/>
-
-  <!-- java project -->
-  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
-            id="1" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2008-12-19 00:00:00.00"/>
-
-  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
-             version="1.0" status="P" islast="[true]"/>
-
-
-  <!-- alert -->
-  <project_measures id="1001" metric_id="5" value="510" snapshot_id="101"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="400"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="WARN" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <!-- php project -->
-  <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
-            id="10" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2012-12-12 04:06:00.00"/>
-
-
-  <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
-             version="3.0" status="P" islast="[true]"/>
-
-  <!-- alert -->
-  <project_measures id="1010" metric_id="5" value="5000" snapshot_id="110"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="OK" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-  <!-- js project -->
-  <projects kee="js_project" long_name="JS project" scope="PRJ" qualifier="TRK" name="JS project"
-            id="20" root_id="[null]"
-            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
-            created_at="2012-12-12 04:06:00.00"/>
-
-
-  <snapshots id="120" project_id="20" root_project_id="20" root_snapshot_id="[null]" parent_snapshot_id="[null]"
-             scope="PRJ" qualifier="TRK" path="" depth="0"
-             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-             created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
-             version="3.0" status="P" islast="[true]"/>
-
-  <!-- alert -->
-  <project_measures id="1020" metric_id="5" value="5000" snapshot_id="120"
-                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
-                    variation_value_4="[null]" variation_value_5="[null]"
-                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
-                    RULE_ID="[null]" text_value="ERROR" tendency="[null]" measure_date="[null]" project_id="[null]"
-                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
-
-
-</dataset>
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilter.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilter.java
new file mode 100644 (file)
index 0000000..7454d8f
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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.measure;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.Qualifiers;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+public class MeasureFilter {
+
+  // conditions on resources
+  private String baseResourceKey;
+
+  // only if baseResourceKey or baseResourceId are set
+  private boolean onBaseResourceChildren = false;
+
+  private List<String> resourceScopes = Collections.emptyList();
+  private List<String> resourceQualifiers = Collections.emptyList();
+  private String resourceKey = null;
+  private String resourceName = null;
+  private Date fromDate = null, toDate = null;
+  private boolean userFavourites = false;
+
+  // conditions on measures
+  private List<MeasureFilterCondition> measureConditions = Lists.newArrayList();
+
+  // sort
+  private MeasureFilterSort sort = new MeasureFilterSort();
+
+  public String getBaseResourceKey() {
+    return baseResourceKey;
+  }
+
+  public MeasureFilter setBaseResourceKey(String s) {
+    this.baseResourceKey = s;
+    return this;
+  }
+
+  public MeasureFilter setOnBaseResourceChildren(boolean b) {
+    this.onBaseResourceChildren = b;
+    return this;
+  }
+
+  public boolean isOnBaseResourceChildren() {
+    return onBaseResourceChildren;
+  }
+
+  public MeasureFilter setResourceScopes(@Nullable List<String> list) {
+    this.resourceScopes = sanitize(list);
+    return this;
+  }
+
+  public MeasureFilter setResourceQualifiers(@Nullable List<String> list) {
+    this.resourceQualifiers = sanitize(list);
+    if (resourceQualifiers.contains(Qualifiers.FILE)) {
+      resourceQualifiers.add(Qualifiers.CLASS);
+    }
+    if (resourceQualifiers.contains(Qualifiers.DIRECTORY)) {
+      resourceQualifiers.add(Qualifiers.PACKAGE);
+    }
+    return this;
+  }
+
+  public MeasureFilter setUserFavourites(boolean b) {
+    this.userFavourites = b;
+    return this;
+  }
+
+  public boolean isOnFavourites() {
+    return userFavourites;
+  }
+
+  public String getResourceName() {
+    return resourceName;
+  }
+
+  public MeasureFilter setResourceName(String s) {
+    this.resourceName = s;
+    return this;
+  }
+
+  public String getResourceKey() {
+    return resourceKey;
+  }
+
+  public MeasureFilter setResourceKey(String s) {
+    this.resourceKey = s;
+    return this;
+  }
+
+  public MeasureFilter addCondition(MeasureFilterCondition condition) {
+    this.measureConditions.add(condition);
+    return this;
+  }
+
+  public MeasureFilter setSortOn(MeasureFilterSort.Field sortField) {
+    this.sort.setField(sortField);
+    return this;
+  }
+
+  public MeasureFilter setSortAsc(boolean b) {
+    this.sort.setAsc(b);
+    return this;
+  }
+
+  public MeasureFilter setSortOnMetric(Metric m) {
+    this.sort.setField(MeasureFilterSort.Field.METRIC);
+    this.sort.setMetric(m);
+    return this;
+  }
+
+  public MeasureFilter setSortOnPeriod(int period) {
+    this.sort.setPeriod(period);
+    return this;
+  }
+
+  public MeasureFilter setFromDate(@Nullable Date d) {
+    this.fromDate = d;
+    return this;
+  }
+
+  public MeasureFilter setToDate(@Nullable Date d) {
+    this.toDate = d;
+    return this;
+  }
+
+  @CheckForNull
+  public Date getFromDate() {
+    return fromDate;
+  }
+
+  @CheckForNull
+  public Date getToDate() {
+    return toDate;
+  }
+
+  public List<String> getResourceScopes() {
+    return resourceScopes;
+  }
+
+  public List<String> getResourceQualifiers() {
+    return resourceQualifiers;
+  }
+
+  public List<MeasureFilterCondition> getMeasureConditions() {
+    return measureConditions;
+  }
+
+  MeasureFilterSort sort() {
+    return sort;
+  }
+
+  public boolean isEmpty() {
+    return resourceQualifiers.isEmpty() && resourceScopes.isEmpty() && StringUtils.isEmpty(baseResourceKey) && !userFavourites;
+  }
+
+  @VisibleForTesting
+  static List<String> sanitize(@Nullable List<String> list) {
+    return isEmptyList(list) ? Collections.<String> emptyList() : Lists.newArrayList(list);
+  }
+
+  private static boolean isEmptyList(@Nullable List<String> list) {
+    boolean blank = false;
+    if (list == null || list.isEmpty() || (list.size() == 1 && Strings.isNullOrEmpty(list.get(0)))) {
+      blank = true;
+    }
+    return blank;
+  }
+
+  @Override
+  public String toString() {
+    return ReflectionToStringBuilder.toString(this);
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterCondition.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterCondition.java
new file mode 100644 (file)
index 0000000..cbb161b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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.measure;
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.measures.Metric;
+
+public class MeasureFilterCondition {
+  public enum Operator {
+    EQUALS("eq", "="), GREATER("gt", ">"), GREATER_OR_EQUALS("gte", ">="), LESS("lt", "<"), LESS_OR_EQUALS("lte", "<="), IN("in", "IN");
+
+    private String code;
+    private String sql;
+
+    private Operator(String code, String sql) {
+      this.code = code;
+      this.sql = sql;
+    }
+
+    public String getSql() {
+      return sql;
+    }
+
+    public static Operator fromCode(String code) {
+      for (Operator operator : values()) {
+        if (operator.code.equals(code)) {
+          return operator;
+        }
+      }
+      throw new IllegalArgumentException("Unknown operator code: " + code);
+    }
+  }
+
+  private final Metric metric;
+  private final Operator operator;
+  private final double value;
+  private final String textValue;
+  private Integer period = null;
+
+  public MeasureFilterCondition(Metric metric, Operator operator, double value) {
+    this.metric = metric;
+    this.operator = operator;
+    this.value = value;
+    this.textValue = null;
+  }
+
+  public MeasureFilterCondition(Metric metric, Operator operator, String textValue) {
+    this.metric = metric;
+    this.operator = operator;
+    this.value = 0;
+    this.textValue = textValue;
+  }
+
+  public MeasureFilterCondition setPeriod(Integer period) {
+    this.period = period;
+    return this;
+  }
+
+  public Metric metric() {
+    return metric;
+  }
+
+  public Operator operator() {
+    return operator;
+  }
+
+  public double value() {
+    return value;
+  }
+
+  public String textValue() {
+    return textValue;
+  }
+
+  public Integer period() {
+    return period;
+  }
+
+  StringBuilder appendSqlColumn(StringBuilder sb, int conditionIndex) {
+    sb.append("pmcond").append(conditionIndex);
+    if (period != null) {
+      sb.append(".variation_value_").append(period).toString();
+    } else if (textValue == null) {
+      sb.append(".value");
+    } else {
+      sb.append(".text_value");
+    }
+    return sb;
+  }
+
+  StringBuilder appendSqlCondition(StringBuilder sql, int conditionIndex) {
+    String table = "pmcond" + conditionIndex;
+    sql.append(" ").append(table).append(".metric_id=");
+    sql.append(metric.getId());
+    sql.append(" AND ");
+    appendSqlColumn(sql, conditionIndex);
+    sql.append(" ").append(operator.getSql()).append(" ");
+    if (textValue == null) {
+      sql.append(value);
+    } else {
+      sql.append(textValue);
+    }
+    sql.append(" AND ");
+    sql.append(table).append(".rule_id IS NULL AND ");
+    sql.append(table).append(".rule_priority IS NULL AND ");
+    sql.append(table).append(".characteristic_id IS NULL AND ");
+    sql.append(table).append(".person_id IS NULL ");
+    return sql;
+  }
+
+  @Override
+  public String toString() {
+    return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterContext.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterContext.java
new file mode 100644 (file)
index 0000000..12d5cb0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.measure;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.core.resource.SnapshotDto;
+
+import javax.annotation.Nullable;
+
+class MeasureFilterContext {
+  private Long userId = null;
+  private SnapshotDto baseSnapshot = null;
+  private String sql;
+  private String data;
+
+  Long getUserId() {
+    return userId;
+  }
+
+  MeasureFilterContext setUserId(@Nullable Long userId) {
+    this.userId = userId;
+    return this;
+  }
+
+  SnapshotDto getBaseSnapshot() {
+    return baseSnapshot;
+  }
+
+  MeasureFilterContext setBaseSnapshot(@Nullable SnapshotDto baseSnapshot) {
+    this.baseSnapshot = baseSnapshot;
+    return this;
+  }
+
+  String getSql() {
+    return sql;
+  }
+
+  MeasureFilterContext setSql(String sql) {
+    this.sql = sql;
+    return this;
+  }
+
+  String getData() {
+    return data;
+  }
+
+  MeasureFilterContext setData(String data) {
+    this.data = data;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+      .append("filter", data)
+      .append("sql", sql)
+      .append("user", userId)
+      .toString();
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterEngine.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterEngine.java
new file mode 100644 (file)
index 0000000..280ab6e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.measure;
+
+import com.google.common.base.Joiner;
+import org.apache.commons.lang.SystemUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.profiling.Profiling;
+import org.sonar.core.profiling.Profiling.Level;
+import org.sonar.core.profiling.StopWatch;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+public class MeasureFilterEngine implements ServerComponent {
+
+  private static final Logger LOG = LoggerFactory.getLogger("org.sonar.MEASURE_FILTER");
+
+  private final MeasureFilterFactory factory;
+  private final MeasureFilterExecutor executor;
+  private final Profiling profiling;
+
+  public MeasureFilterEngine(MeasureFilterFactory factory, MeasureFilterExecutor executor, Profiling profiling) {
+    this.executor = executor;
+    this.factory = factory;
+    this.profiling = profiling;
+  }
+
+  public MeasureFilterResult execute(Map<String, Object> filterMap, @Nullable Long userId) {
+    StopWatch watch = profiling.start("measures", Level.BASIC);
+    StopWatch sqlWatch = null;
+    MeasureFilterResult result = new MeasureFilterResult();
+    MeasureFilterContext context = new MeasureFilterContext();
+    context.setUserId(userId);
+    context.setData(String.format("{%s}", Joiner.on('|').withKeyValueSeparator("=").join(filterMap)));
+    try {
+      MeasureFilter filter = factory.create(filterMap);
+      sqlWatch = profiling.start("sql", Level.FULL);
+      List<MeasureFilterRow> rows = executor.execute(filter, context);
+      result.setRows(rows);
+
+    } catch (NumberFormatException e) {
+      result.setError(MeasureFilterResult.Error.VALUE_SHOULD_BE_A_NUMBER);
+      LOG.debug("Value selected for the metric should be a number: " + context);
+    } catch (Exception e) {
+      result.setError(MeasureFilterResult.Error.UNKNOWN);
+      LOG.error("Fail to execute measure filter: " + context, e);
+    } finally {
+      if (sqlWatch != null) {
+        sqlWatch.stop(context.getSql());
+      }
+      watch.stop(log(context, result));
+    }
+    return result;
+  }
+
+  private String log(MeasureFilterContext context, MeasureFilterResult result) {
+    StringBuilder log = new StringBuilder();
+    log.append(SystemUtils.LINE_SEPARATOR);
+    log.append("request: ").append(context.getData()).append(SystemUtils.LINE_SEPARATOR);
+    log.append(" result: ").append(result.toString());
+    return log.toString();
+  }
+
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterExecutor.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterExecutor.java
new file mode 100644 (file)
index 0000000..015d304
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.measure;
+
+import com.google.common.base.Strings;
+import org.apache.commons.dbutils.DbUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.persistence.Database;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.resource.ResourceDao;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+public class MeasureFilterExecutor implements ServerComponent {
+
+  private MyBatis mybatis;
+  private Database database;
+  private ResourceDao resourceDao;
+
+  public MeasureFilterExecutor(MyBatis mybatis, Database database, ResourceDao resourceDao) {
+    this.mybatis = mybatis;
+    this.database = database;
+    this.resourceDao = resourceDao;
+  }
+
+  public List<MeasureFilterRow> execute(MeasureFilter filter, MeasureFilterContext context) throws SQLException {
+    if (filter.isEmpty()) {
+      return Collections.emptyList();
+    }
+
+    List<MeasureFilterRow> rows;
+    SqlSession session = null;
+    Connection connection = null;
+    try {
+      session = mybatis.openSession(false);
+      prepareContext(context, filter, session);
+
+      if (isValid(filter, context)) {
+        MeasureFilterSql sql = new MeasureFilterSql(database, filter, context);
+        context.setSql(sql.sql());
+        connection = session.getConnection();
+        rows = sql.execute(connection);
+      } else {
+        rows = Collections.emptyList();
+      }
+    } finally {
+      MyBatis.closeQuietly(session);
+      // connection is supposed to be closed by the session
+      DbUtils.closeQuietly(connection);
+    }
+
+    return rows;
+  }
+
+  private void prepareContext(MeasureFilterContext context, MeasureFilter filter, SqlSession session) {
+    if (filter.getBaseResourceKey() != null) {
+      context.setBaseSnapshot(resourceDao.getLastSnapshot(filter.getBaseResourceKey(), session));
+    }
+  }
+
+  static boolean isValid(MeasureFilter filter, MeasureFilterContext context) {
+    boolean valid = Strings.isNullOrEmpty(filter.getBaseResourceKey()) || context.getBaseSnapshot()!=null;
+    valid &= !(filter.isOnBaseResourceChildren() && context.getBaseSnapshot() == null);
+    valid &= !(filter.isOnFavourites() && context.getUserId() == null);
+    valid &= validateMeasureConditions(filter);
+    valid &= validateSort(filter);
+    return valid;
+  }
+
+  private static boolean validateMeasureConditions(MeasureFilter filter) {
+    boolean valid = true;
+    for (MeasureFilterCondition condition : filter.getMeasureConditions()) {
+      if (condition.period() != null && condition.period() < 1) {
+        valid = false;
+      }
+      if (condition.metric() == null) {
+        valid = false;
+      }
+    }
+    return valid;
+  }
+
+  private static boolean validateSort(MeasureFilter filter) {
+    boolean valid = true;
+    if (filter.sort().period() != null && filter.sort().period() < 1) {
+      valid = false;
+    }
+    if (filter.sort().onMeasures() && filter.sort().metric() == null) {
+      valid = false;
+    }
+    return valid;
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterFactory.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterFactory.java
new file mode 100644 (file)
index 0000000..06d5143
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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.measure;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class MeasureFilterFactory implements ServerComponent {
+
+  private final MetricFinder metricFinder;
+  private final System2 system;
+
+  public MeasureFilterFactory(MetricFinder metricFinder, System2 system) {
+    this.metricFinder = metricFinder;
+    this.system = system;
+  }
+
+  public MeasureFilter create(Map<String, Object> properties) {
+    MeasureFilter filter = new MeasureFilter();
+    filter.setBaseResourceKey((String) properties.get("base"));
+    filter.setResourceScopes(toList(properties.get("scopes")));
+    filter.setResourceQualifiers(toList(properties.get("qualifiers")));
+    MeasureFilterCondition condition = alertToCondition(toList(properties.get("alertLevels")));
+    if (condition != null) {
+      filter.addCondition(condition);
+    }
+    String onBaseComponents = (String) properties.get("onBaseComponents");
+    if (onBaseComponents != null) {
+      filter.setOnBaseResourceChildren(Boolean.valueOf(onBaseComponents));
+    }
+    filter.setResourceName((String) properties.get("nameSearch"));
+    filter.setResourceKey((String) properties.get("keySearch"));
+    String onFavourites = (String) properties.get("onFavourites");
+    if (onFavourites != null) {
+      filter.setUserFavourites(Boolean.valueOf(onFavourites));
+    }
+    fillDateConditions(filter, properties);
+    fillSorting(filter, properties);
+    fillMeasureConditions(properties, filter);
+    return filter;
+  }
+
+  private void fillDateConditions(MeasureFilter filter, Map<String, Object> properties) {
+    String fromDate = (String) properties.get("fromDate");
+    if (fromDate != null) {
+      filter.setFromDate(toDate(fromDate));
+    } else {
+      filter.setFromDate(toDays((String) properties.get("ageMaxDays")));
+    }
+    String toDate = (String) properties.get("toDate");
+    if (toDate != null) {
+      filter.setToDate(toDate(toDate));
+    } else {
+      filter.setToDate(toDays((String) properties.get("ageMinDays")));
+    }
+  }
+
+  private void fillMeasureConditions(Map<String, Object> properties, MeasureFilter filter) {
+    for (int index = 1; index <= 3; index++) {
+      MeasureFilterCondition condition = toCondition(properties, index);
+      if (condition != null) {
+        filter.addCondition(condition);
+      }
+    }
+  }
+
+  private void fillSorting(MeasureFilter filter, Map<String, Object> properties) {
+    String s = (String) properties.get("sort");
+    if (s != null) {
+      if (StringUtils.startsWith(s, "metric:")) {
+        String[] fields = StringUtils.split(s, ':');
+        Metric metric = metricFinder.findByKey(fields[1]);
+        if (metric != null) {
+          filter.setSortOnMetric(metric);
+          if (fields.length == 3) {
+            filter.setSortOnPeriod(Integer.parseInt(fields[2]));
+          }
+        }
+      } else {
+        filter.setSortOn(MeasureFilterSort.Field.valueOf(s.toUpperCase()));
+      }
+    }
+
+    if (properties.containsKey("asc")) {
+      filter.setSortAsc(Boolean.valueOf((String) properties.get("asc")));
+    }
+  }
+
+  @CheckForNull
+  private MeasureFilterCondition toCondition(Map<String, Object> props, int index) {
+    MeasureFilterCondition condition = null;
+    String metricKey = (String) props.get("c" + index + "_metric");
+    String op = (String) props.get("c" + index + "_op");
+    String val = (String) props.get("c" + index + "_val");
+    if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
+      Metric metric = metricFinder.findByKey(metricKey);
+      MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
+      condition = new MeasureFilterCondition(metric, operator, Double.parseDouble(val));
+      String period = (String) props.get("c" + index + "_period");
+      if (period != null) {
+        condition.setPeriod(Integer.parseInt(period));
+      }
+    }
+    return condition;
+  }
+
+  @CheckForNull
+  private MeasureFilterCondition alertToCondition(List<String> alertLevels) {
+    if (alertLevels == null || alertLevels.isEmpty()) {
+      return null;
+    }
+    MeasureFilterCondition condition = null;
+    String metricKey = CoreMetrics.ALERT_STATUS_KEY;
+    String op = "in";
+    List<String> alertLevelsUppercase = Lists.transform(alertLevels, new Function<String, String>() {
+      @Override
+      public String apply(String input) {
+        return input != null ? input.toUpperCase() : "";
+      }
+    });
+    String val = "('" + Joiner.on("', '").join(alertLevelsUppercase) + "')";
+    if (!Strings.isNullOrEmpty(metricKey) && !Strings.isNullOrEmpty(op) && !Strings.isNullOrEmpty(val)) {
+      Metric metric = metricFinder.findByKey(metricKey);
+      MeasureFilterCondition.Operator operator = MeasureFilterCondition.Operator.fromCode(op);
+      condition = new MeasureFilterCondition(metric, operator, val);
+    }
+    return condition;
+  }
+
+  private List<String> toList(@Nullable Object obj) {
+    List<String> result = null;
+    if (obj != null) {
+      if (obj instanceof String) {
+        result = Arrays.asList((String) obj);
+      } else {
+        result = (List<String>) obj;
+      }
+    }
+    return result;
+  }
+
+  @CheckForNull
+  private Date toDate(@Nullable String date) {
+    if (date != null) {
+      return DateUtils.parseDate(date);
+    }
+    return null;
+  }
+
+  @CheckForNull
+  private Date toDays(@Nullable String s) {
+    if (s != null) {
+      int days = Integer.valueOf(s);
+      Date date = org.apache.commons.lang.time.DateUtils.truncate(new Date(system.now()), Calendar.DATE);
+      date = org.apache.commons.lang.time.DateUtils.addDays(date, -days);
+      return date;
+    }
+    return null;
+  }
+
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterResult.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterResult.java
new file mode 100644 (file)
index 0000000..80e0612
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.measure;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+
+public class MeasureFilterResult {
+
+  public static enum Error {
+    UNKNOWN, VALUE_SHOULD_BE_A_NUMBER
+  }
+
+  private List<MeasureFilterRow> rows = null;
+  private Error error = null;
+
+  MeasureFilterResult() {
+  }
+
+  public List<MeasureFilterRow> getRows() {
+    return rows;
+  }
+
+  public Error getError() {
+    return error;
+  }
+
+  MeasureFilterResult setRows(@Nullable List<MeasureFilterRow> rows) {
+    this.rows = rows;
+    return this;
+  }
+
+  MeasureFilterResult setError(@Nullable Error err) {
+    this.error = err;
+    return this;
+  }
+
+  public boolean isSuccess() {
+    return error == null;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    if (rows != null) {
+      sb.append(rows.size()).append(" rows, ");
+    }
+    if (error != null) {
+      sb.append("error=").append(error).append(", ");
+    }
+    return sb.toString();
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterRow.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterRow.java
new file mode 100644 (file)
index 0000000..bff5011
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.measure;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.sql.Timestamp;
+
+public class MeasureFilterRow {
+  private final long snapshotId;
+  private final long resourceId;
+  private final long resourceRootId;
+  private String sortText = null;
+  private Timestamp sortDate = null;
+  private Double sortDouble = null;
+
+  MeasureFilterRow(long snapshotId, long resourceId, long resourceRootId) {
+    this.snapshotId = snapshotId;
+    this.resourceId = resourceId;
+    this.resourceRootId = resourceRootId;
+  }
+
+  public long getSnapshotId() {
+    return snapshotId;
+  }
+
+  public long getResourceId() {
+    return resourceId;
+  }
+
+  public long getResourceRootId() {
+    return resourceRootId;
+  }
+
+  public String getSortText() {
+    return sortText;
+  }
+
+  void setSortText(String s) {
+    this.sortText = StringUtils.defaultString(s);
+  }
+
+  Timestamp getSortDate() {
+    return sortDate;
+  }
+
+  void setSortDate(Timestamp sortDate) {
+    this.sortDate = sortDate;
+  }
+
+  Double getSortDouble() {
+    return sortDouble;
+  }
+
+  void setSortDouble(Double sortDouble) {
+    this.sortDouble = sortDouble;
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSort.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSort.java
new file mode 100644 (file)
index 0000000..0cbc114
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.measure;
+
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+
+class MeasureFilterSort {
+  public static enum Field {
+    KEY, NAME, VERSION, METRIC, SHORT_NAME, DESCRIPTION,
+    // Sort by last analysis date
+    DATE,
+    // Sort by project creation date
+    PROJECT_CREATION_DATE
+  }
+
+  private Field field = Field.NAME;
+  private Metric metric = null;
+  private Integer period = null;
+  private boolean asc = true;
+
+  MeasureFilterSort() {
+  }
+
+  void setField(Field field) {
+    this.field = field;
+  }
+
+  void setMetric(Metric metric) {
+    this.field = Field.METRIC;
+    this.metric = metric;
+  }
+
+  Integer period() {
+    return period;
+  }
+
+  void setPeriod(Integer period) {
+    this.period = period;
+  }
+
+  void setAsc(boolean asc) {
+    this.asc = asc;
+  }
+
+  public Field field() {
+    return field;
+  }
+
+  boolean onMeasures() {
+    return field == Field.METRIC;
+  }
+
+  Metric metric() {
+    return metric;
+  }
+
+  boolean isOnMeasure() {
+    return metric != null;
+  }
+
+  boolean isOnNumericMeasure() {
+    return metric != null && metric.isNumericType();
+  }
+
+  boolean isOnDate() {
+    return Field.DATE.equals(field) || Field.PROJECT_CREATION_DATE.equals(field);
+  }
+
+  boolean isOnAlert() {
+    return metric != null && metric.getKey().equals(CoreMetrics.ALERT_STATUS_KEY);
+  }
+
+  boolean isAsc() {
+    return asc;
+  }
+
+  String column() {
+    // only numeric metrics can be sorted by database, else results are sorted programmatically.
+    String column;
+    switch (field) {
+      case KEY:
+        column = "p.kee";
+        break;
+      case NAME:
+        column = "p.long_name";
+        break;
+      case SHORT_NAME:
+        column = "p.name";
+        break;
+      case DESCRIPTION:
+        column = "p.description";
+        break;
+      case VERSION:
+        column = "s.version";
+        break;
+      case DATE:
+        column = "s.created_at";
+        break;
+      case PROJECT_CREATION_DATE:
+        column = "p.created_at";
+        break;
+      case METRIC:
+        column = getMetricColumn();
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported sorting: " + field);
+    }
+    return column;
+  }
+
+  private String getMetricColumn(){
+    if (metric.isNumericType()) {
+      return period != null ? "pmsort.variation_value_" + period : "pmsort.value";
+    } else {
+      return "pmsort.text_value";
+    }
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java b/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java
new file mode 100644 (file)
index 0000000..fdb4296
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * 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.measure;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import org.apache.commons.dbutils.DbUtils;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.core.persistence.Database;
+import org.sonar.core.persistence.dialect.MsSql;
+import org.sonar.core.persistence.dialect.Oracle;
+import org.sonar.core.resource.SnapshotDto;
+
+import javax.annotation.Nullable;
+
+import java.sql.*;
+import java.sql.Date;
+import java.util.*;
+
+class MeasureFilterSql {
+
+  private final Database database;
+  private final MeasureFilter filter;
+  private final MeasureFilterContext context;
+  private final String sql;
+  private final List<Date> dateParameters = Lists.newArrayList();
+
+  MeasureFilterSql(Database database, MeasureFilter filter, MeasureFilterContext context) {
+    this.database = database;
+    this.filter = filter;
+    this.context = context;
+    this.sql = generateSql();
+  }
+
+  List<MeasureFilterRow> execute(Connection connection) throws SQLException {
+    PreparedStatement statement = connection.prepareStatement(sql);
+    ResultSet rs = null;
+    try {
+      for (int index = 0; index < dateParameters.size(); index++) {
+        statement.setDate(index + 1, dateParameters.get(index));
+      }
+      rs = statement.executeQuery();
+      return process(rs);
+
+    } finally {
+      DbUtils.closeQuietly(rs);
+      DbUtils.closeQuietly(statement);
+    }
+  }
+
+  String sql() {
+    return sql;
+  }
+
+  private String generateSql() {
+    StringBuilder sb = new StringBuilder(1000);
+    sb.append("SELECT s.id, s.project_id, s.root_project_id, ");
+    sb.append(filter.sort().column());
+    sb.append(" FROM snapshots s INNER JOIN projects p ON s.project_id=p.id ");
+
+    for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
+      MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
+      sb.append(" INNER JOIN project_measures pmcond").append(index);
+      sb.append(" ON s.id=pmcond").append(index).append(".snapshot_id AND ");
+      condition.appendSqlCondition(sb, index);
+    }
+
+    if (filter.isOnFavourites()) {
+      sb.append(" INNER JOIN properties props ON props.resource_id=s.project_id ");
+    }
+
+    if (filter.sort().isOnMeasure()) {
+      sb.append(" LEFT OUTER JOIN project_measures pmsort ON s.id=pmsort.snapshot_id AND pmsort.metric_id=");
+      sb.append(filter.sort().metric().getId());
+      sb.append(" AND pmsort.rule_id IS NULL AND pmsort.rule_priority IS NULL AND pmsort.characteristic_id IS NULL AND pmsort.person_id IS NULL ");
+    }
+
+    sb.append(" WHERE ");
+    appendResourceConditions(sb);
+
+    for (int index = 0; index < filter.getMeasureConditions().size(); index++) {
+      MeasureFilterCondition condition = filter.getMeasureConditions().get(index);
+      sb.append(" AND ");
+      condition.appendSqlCondition(sb, index);
+    }
+
+    return sb.toString();
+  }
+
+  private void appendResourceConditions(StringBuilder sb) {
+    sb.append(" s.status='P' AND s.islast=").append(database.getDialect().getTrueSqlValue());
+    if (context.getBaseSnapshot() == null) {
+      sb.append(" AND p.copy_resource_id IS NULL ");
+    }
+    if (!filter.getResourceQualifiers().isEmpty()) {
+      sb.append(" AND s.qualifier IN ");
+      appendInStatement(filter.getResourceQualifiers(), sb);
+    }
+    if (!filter.getResourceScopes().isEmpty()) {
+      sb.append(" AND s.scope IN ");
+      appendInStatement(filter.getResourceScopes(), sb);
+    }
+    appendDateConditions(sb);
+    appendFavouritesCondition(sb);
+    appendResourceNameCondition(sb);
+    appendResourceKeyCondition(sb);
+    appendResourceBaseCondition(sb);
+  }
+
+  private void appendDateConditions(StringBuilder sb) {
+    java.util.Date fromDate = filter.getFromDate();
+    if (fromDate != null) {
+      sb.append(" AND s.created_at >= ? ");
+      dateParameters.add(new Date(fromDate.getTime()));
+    }
+    java.util.Date toDate = filter.getToDate();
+    if (toDate != null) {
+      sb.append(" AND s.created_at <= ? ");
+      dateParameters.add(new Date(toDate.getTime()));
+    }
+  }
+
+  private void appendFavouritesCondition(StringBuilder sb) {
+    if (filter.isOnFavourites()) {
+      sb.append(" AND props.prop_key='favourite' AND props.resource_id IS NOT NULL AND props.user_id=");
+      sb.append(context.getUserId());
+      sb.append(" ");
+    }
+  }
+
+  private void appendResourceBaseCondition(StringBuilder sb) {
+    SnapshotDto baseSnapshot = context.getBaseSnapshot();
+    if (baseSnapshot != null) {
+      if (filter.isOnBaseResourceChildren()) {
+        sb.append(" AND s.parent_snapshot_id=").append(baseSnapshot.getId());
+      } else {
+        Long rootSnapshotId = baseSnapshot.getRootId() != null ? baseSnapshot.getRootId() : baseSnapshot.getId();
+        sb.append(" AND s.root_snapshot_id=").append(rootSnapshotId);
+        sb.append(" AND s.path LIKE '").append(StringUtils.defaultString(baseSnapshot.getPath())).append(baseSnapshot.getId()).append(".%'");
+      }
+    }
+  }
+
+  private void appendResourceKeyCondition(StringBuilder sb) {
+    if (StringUtils.isNotBlank(filter.getResourceKey())) {
+      sb.append(" AND UPPER(p.kee) LIKE '%");
+      sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.upperCase(filter.getResourceKey()))));
+      sb.append("%'");
+      appendEscapeForSomeDb(sb);
+    }
+  }
+
+  private void appendResourceNameCondition(StringBuilder sb) {
+    if (StringUtils.isNotBlank(filter.getResourceName())) {
+      sb.append(" AND s.project_id IN (SELECT rindex.resource_id FROM resource_index rindex WHERE rindex.kee LIKE '");
+      sb.append(escapePercentAndUnderscrore(StringEscapeUtils.escapeSql(StringUtils.lowerCase(filter.getResourceName()))));
+      sb.append("%'");
+      appendEscapeForSomeDb(sb);
+      if (!filter.getResourceQualifiers().isEmpty()) {
+        sb.append(" AND rindex.qualifier IN ");
+        appendInStatement(filter.getResourceQualifiers(), sb);
+      }
+      sb.append(") ");
+    }
+  }
+
+  List<MeasureFilterRow> process(ResultSet rs) throws SQLException {
+    List<MeasureFilterRow> rows = Lists.newArrayList();
+    RowProcessor rowProcessor;
+    if (filter.sort().isOnNumericMeasure()) {
+      rowProcessor = new NumericSortRowProcessor();
+    } else if (filter.sort().isOnDate()) {
+      rowProcessor = new DateSortRowProcessor();
+    } else if (filter.sort().isOnAlert()) {
+      rowProcessor = new AlertSortRowProcessor();
+    } else {
+      rowProcessor = new TextSortRowProcessor();
+    }
+
+    while (rs.next()) {
+      rows.add(rowProcessor.fetch(rs));
+    }
+
+    return rowProcessor.sort(rows, filter.sort().isAsc());
+  }
+
+  private static void appendInStatement(List<String> values, StringBuilder to) {
+    to.append(" (");
+    for (int i = 0; i < values.size(); i++) {
+      if (i > 0) {
+        to.append(",");
+      }
+      to.append("'");
+      to.append(StringEscapeUtils.escapeSql(values.get(i)));
+      to.append("'");
+    }
+    to.append(") ");
+  }
+
+  /**
+   * Replace escape percent and underscore by adding a slash just before
+   */
+  private String escapePercentAndUnderscrore(String value){
+    return value.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_");
+  }
+
+  private void appendEscapeForSomeDb(StringBuilder sb){
+    if (database.getDialect().getId().equals(Oracle.ID) || database.getDialect().getId().equals(MsSql.ID)) {
+      sb.append(" ESCAPE '\\'");
+    }
+  }
+
+  abstract static class RowProcessor {
+    abstract Function sortFieldFunction();
+
+    abstract Ordering sortFieldOrdering(boolean ascending);
+
+    abstract MeasureFilterRow fetch(ResultSet rs) throws SQLException;
+
+    final List<MeasureFilterRow> sort(List<MeasureFilterRow> rows, boolean ascending) {
+      Ordering<MeasureFilterRow> ordering = sortFieldOrdering(ascending).onResultOf(sortFieldFunction());
+      return ordering.immutableSortedCopy(rows);
+    }
+  }
+
+  static class TextSortRowProcessor extends RowProcessor {
+    MeasureFilterRow fetch(ResultSet rs) throws SQLException {
+      MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
+      row.setSortText(rs.getString(4));
+      return row;
+    }
+
+    Function sortFieldFunction() {
+      return new Function<MeasureFilterRow, String>() {
+        public String apply(MeasureFilterRow row) {
+          return row.getSortText();
+        }
+      };
+    }
+
+    Ordering sortFieldOrdering(boolean ascending) {
+      Ordering<String> ordering = Ordering.from(String.CASE_INSENSITIVE_ORDER);
+      if (!ascending) {
+        ordering = ordering.reverse();
+      }
+      return ordering;
+    }
+  }
+
+  static class AlertSortRowProcessor extends TextSortRowProcessor {
+    Function sortFieldFunction() {
+      return new Function<MeasureFilterRow, Integer>() {
+        public Integer apply(MeasureFilterRow row) {
+          return ImmutableList.of("OK", "WARN", "ERROR").indexOf(row.getSortText());
+        }
+      };
+    }
+
+    @Override
+    Ordering sortFieldOrdering(boolean ascending) {
+      Ordering<Integer> ordering = Ordering.<Integer>natural().nullsLast();
+      if (!ascending) {
+        ordering = ordering.reverse();
+      }
+      return ordering;
+    }
+  }
+
+  static class NumericSortRowProcessor extends RowProcessor {
+    MeasureFilterRow fetch(ResultSet rs) throws SQLException {
+      MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
+      double value = rs.getDouble(4);
+      if (!rs.wasNull()) {
+        row.setSortDouble(value);
+      }
+      return row;
+    }
+
+    Function sortFieldFunction() {
+      return new Function<MeasureFilterRow, Double>() {
+        public Double apply(MeasureFilterRow row) {
+          return row.getSortDouble();
+        }
+      };
+    }
+
+    Ordering sortFieldOrdering(boolean ascending) {
+      return ascending ? Ordering.natural().nullsLast() : Ordering.natural().reverse().nullsLast();
+    }
+  }
+
+  static class DateSortRowProcessor extends RowProcessor {
+    MeasureFilterRow fetch(ResultSet rs) throws SQLException {
+      MeasureFilterRow row = new MeasureFilterRow(rs.getLong(1), rs.getLong(2), rs.getLong(3));
+      row.setSortDate(rs.getTimestamp(4));
+      return row;
+    }
+
+    Function sortFieldFunction() {
+      return new Function<MeasureFilterRow, Timestamp>() {
+        public Timestamp apply(MeasureFilterRow row) {
+          return row.getSortDate();
+        }
+      };
+    }
+
+    Ordering sortFieldOrdering(boolean ascending) {
+      return newObjectOrdering(ascending);
+    }
+  }
+
+  private static Ordering newObjectOrdering(boolean ascending) {
+    if (ascending) {
+      return Ordering.from(new Comparator<Comparable>() {
+        public int compare(@Nullable Comparable left, @Nullable Comparable right) {
+          if (left == null) {
+            return 1;
+          }
+          if (right == null) {
+            return -1;
+          }
+
+          return left.compareTo(right);
+        }
+      });
+    }
+    return Ordering.from(new Comparator<Comparable>() {
+      public int compare(@Nullable Comparable left, @Nullable Comparable right) {
+        if (left == null) {
+          return 1;
+        }
+        if (right == null) {
+          return -1;
+        }
+
+        return -left.compareTo(right);
+      }
+    });
+  }
+}
+
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/package-info.java b/sonar-server/src/main/java/org/sonar/server/measure/package-info.java
new file mode 100644 (file)
index 0000000..14240ae
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.measure;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-server/src/main/java/org/sonar/server/measure/ws/package-info.java b/sonar-server/src/main/java/org/sonar/server/measure/ws/package-info.java
new file mode 100644 (file)
index 0000000..fca450a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.measure.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 0256c391473a4fe89a1bed9519d71c26b50e3cdd..b339f752715f2bbda0a67d8774b3737c3f489273 100644 (file)
@@ -49,9 +49,10 @@ import org.sonar.core.issue.IssueNotifications;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.workflow.FunctionExecutor;
 import org.sonar.core.issue.workflow.IssueWorkflow;
-import org.sonar.core.measure.MeasureFilterEngine;
-import org.sonar.core.measure.MeasureFilterExecutor;
-import org.sonar.core.measure.MeasureFilterFactory;
+import org.sonar.core.measure.db.MeasureFilterDao;
+import org.sonar.server.measure.MeasureFilterEngine;
+import org.sonar.server.measure.MeasureFilterExecutor;
+import org.sonar.server.measure.MeasureFilterFactory;
 import org.sonar.core.metric.DefaultMetricFinder;
 import org.sonar.core.notification.DefaultNotificationManager;
 import org.sonar.core.permission.PermissionFacade;
@@ -201,8 +202,9 @@ class ServerComponents {
       System2.INSTANCE,
       RuleDao.class,
       ActiveRuleDao.class,
-      DbClient.class
-    ));
+      DbClient.class,
+      MeasureFilterDao.class
+      ));
     components.addAll(CorePropertyDefinitions.all());
     components.addAll(DatabaseMigrations.CLASSES);
     components.addAll(DaoUtils.getDaoClasses());
index b3f764ebc58f0466d2319b64d0bfa7bc2dd96e89..ecad707f0064d6b7b80fa385b03105175db7a3d6 100644 (file)
@@ -37,8 +37,8 @@ import org.sonar.api.test.TestPlan;
 import org.sonar.api.test.Testable;
 import org.sonar.api.web.*;
 import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.measure.MeasureFilterEngine;
-import org.sonar.core.measure.MeasureFilterResult;
+import org.sonar.server.measure.MeasureFilterEngine;
+import org.sonar.server.measure.MeasureFilterResult;
 import org.sonar.core.persistence.Database;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.purge.PurgeDao;
diff --git a/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterConditionTest.java b/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterConditionTest.java
new file mode 100644 (file)
index 0000000..5f5ec58
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.measure;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.measures.Metric;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterConditionTest {
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void create_operator_from_code() {
+    assertThat(MeasureFilterCondition.Operator.fromCode("eq")).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
+    assertThat(MeasureFilterCondition.Operator.fromCode("lte")).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
+  }
+
+  @Test
+  public void fail_if_operator_code_not_found() {
+    thrown.expect(IllegalArgumentException.class);
+    MeasureFilterCondition.Operator.fromCode("xxx");
+  }
+
+  @Test
+  public void operator_sql() {
+    assertThat(MeasureFilterCondition.Operator.EQUALS.getSql()).isEqualTo("=");
+    assertThat(MeasureFilterCondition.Operator.LESS_OR_EQUALS.getSql()).isEqualTo("<=");
+    assertThat(MeasureFilterCondition.Operator.GREATER.getSql()).isEqualTo(">");
+  }
+
+  @Test
+  public void value_condition() {
+    Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
+    ncloc.setId(123);
+    MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.GREATER, 10.0);
+
+    assertThat(condition.metric()).isEqualTo(ncloc);
+    assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER);
+    assertThat(condition.period()).isNull();
+    assertThat(condition.value()).isEqualTo(10.0);
+    assertThat(condition.textValue()).isNull();
+    assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.value");
+    assertThat(condition.toString()).isNotEmpty();
+    assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.value > 10.0 AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
+  }
+
+  @Test
+  public void variation_condition() {
+    Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
+    ncloc.setId(123);
+    MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 10.0);
+    condition.setPeriod(3);
+
+    assertThat(condition.metric()).isEqualTo(ncloc);
+    assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.LESS_OR_EQUALS);
+    assertThat(condition.period()).isEqualTo(3);
+    assertThat(condition.value()).isEqualTo(10.0);
+    assertThat(condition.appendSqlColumn(new StringBuilder(), 2).toString()).isEqualTo("pmcond2.variation_value_3");
+    assertThat(condition.toString()).isNotEmpty();
+    assertThat(condition.appendSqlCondition(new StringBuilder(), 2).toString()).isEqualTo(" pmcond2.metric_id=123 AND pmcond2.variation_value_3 <= 10.0 AND pmcond2.rule_id IS NULL AND pmcond2.rule_priority IS NULL AND pmcond2.characteristic_id IS NULL AND pmcond2.person_id IS NULL ");
+  }
+
+  @Test
+  public void text_value_condition() {
+    Metric ncloc = new Metric.Builder("ncloc", "NCLOC", Metric.ValueType.INT).create();
+    ncloc.setId(123);
+    MeasureFilterCondition condition = new MeasureFilterCondition(ncloc, MeasureFilterCondition.Operator.EQUALS, "\"foo\"");
+
+    assertThat(condition.metric()).isEqualTo(ncloc);
+    assertThat(condition.operator()).isEqualTo(MeasureFilterCondition.Operator.EQUALS);
+    assertThat(condition.period()).isNull();
+    assertThat(condition.value()).isEqualTo(0);
+    assertThat(condition.textValue()).isEqualTo("\"foo\"");
+    assertThat(condition.appendSqlColumn(new StringBuilder(), 1).toString()).isEqualTo("pmcond1.text_value");
+    assertThat(condition.toString()).isNotEmpty();
+    assertThat(condition.appendSqlCondition(new StringBuilder(), 1).toString()).isEqualTo(" pmcond1.metric_id=123 AND pmcond1.text_value = \"foo\" AND pmcond1.rule_id IS NULL AND pmcond1.rule_priority IS NULL AND pmcond1.characteristic_id IS NULL AND pmcond1.person_id IS NULL ");
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterContextTest.java b/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterContextTest.java
new file mode 100644 (file)
index 0000000..0a3edb1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.measure;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterContextTest {
+  @Test
+  public void test_empty_toString() {
+    MeasureFilterContext context = new MeasureFilterContext();
+    assertThat(context.toString()).isNotEmpty();
+  }
+
+  @Test
+  public void test_toString() {
+    MeasureFilterContext context = new MeasureFilterContext();
+    context.setData("{qualifiers=TRK}");
+    context.setSql("SELECT *");
+    context.setUserId(50L);
+    assertThat(context.toString()).isEqualTo("MeasureFilterContext[filter={qualifiers=TRK},sql=SELECT *,user=50]");
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterEngineTest.java b/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterEngineTest.java
new file mode 100644 (file)
index 0000000..285bc40
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.measure;
+
+import com.google.common.collect.ImmutableMap;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.core.profiling.Profiling;
+
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MeasureFilterEngineTest {
+
+  @Test
+  public void should_create_and_execute_filter() throws Exception {
+    Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
+    MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
+    MeasureFilter filter = new MeasureFilter();
+    when(factory.create(filterMap)).thenReturn(filter);
+    MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
+
+    MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
+
+    final long userId = 50L;
+    engine.execute(filterMap, userId);
+    verify(executor).execute(refEq(filter), argThat(new BaseMatcher<MeasureFilterContext>() {
+      public boolean matches(Object o) {
+        MeasureFilterContext context = (MeasureFilterContext) o;
+        return "{qualifiers=TRK}".equals(context.getData()) && context.getUserId() == userId;
+      }
+
+      public void describeTo(Description description) {
+      }
+    }));
+  }
+
+  @Test
+  public void keep_error_but_do_not_fail() throws Exception {
+    Map<String, Object> filterMap = ImmutableMap.of("qualifiers", (Object) "TRK");
+    MeasureFilterFactory factory = mock(MeasureFilterFactory.class);
+    when(factory.create(filterMap)).thenThrow(new IllegalArgumentException());
+    MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
+
+    MeasureFilterEngine engine = new MeasureFilterEngine(factory, executor, new Profiling(new Settings()));
+    MeasureFilterResult result = engine.execute(filterMap, 50L);
+
+    assertThat(result.isSuccess()).isFalse();
+    assertThat(result.getError()).isEqualTo(MeasureFilterResult.Error.UNKNOWN);
+    assertThat(result.getRows()).isNull();
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterExecutorTest.java b/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterExecutorTest.java
new file mode 100644 (file)
index 0000000..babee47
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+ * 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.measure;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.persistence.TestDatabase;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.SnapshotDto;
+
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterExecutorTest {
+  private static final long JAVA_PROJECT_ID = 1L;
+  private static final long JAVA_FILE_BIG_ID = 3L;
+  private static final long JAVA_FILE_TINY_ID = 4L;
+  private static final long JAVA_PROJECT_SNAPSHOT_ID = 101L;
+  private static final long JAVA_FILE_BIG_SNAPSHOT_ID = 103L;
+  private static final long JAVA_FILE_TINY_SNAPSHOT_ID = 104L;
+  private static final long JAVA_PACKAGE_SNAPSHOT_ID = 102L;
+  private static final long PHP_PROJECT_ID = 10L;
+  private static final long PHP_SNAPSHOT_ID = 110L;
+  private static final Metric METRIC_LINES = new Metric.Builder("lines", "Lines", Metric.ValueType.INT).create().setId(1);
+  private static final Metric METRIC_PROFILE = new Metric.Builder("profile", "Profile", Metric.ValueType.STRING).create().setId(2);
+  private static final Metric METRIC_COVERAGE = new Metric.Builder("coverage", "Coverage", Metric.ValueType.FLOAT).create().setId(3);
+  private static final Metric METRIC_UNKNOWN = new Metric.Builder("unknown", "Unknown", Metric.ValueType.FLOAT).create().setId(4);
+
+  private MeasureFilterExecutor executor;
+
+  @ClassRule
+  public static TestDatabase db = new TestDatabase();
+
+  @Before
+  public void before() {
+    executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis()));
+  }
+
+  @Test
+  public void should_return_empty_results_if_empty_filter() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter();
+    assertThat(filter.isEmpty()).isTrue();
+
+    assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
+  }
+
+  @Test
+  public void invalid_filter_should_not_return_results() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setUserFavourites(true);
+    // anonymous user does not have favourites
+    assertThat(executor.execute(filter, new MeasureFilterContext())).isEmpty();
+  }
+
+  @Test
+  public void filter_is_not_valid_if_missing_base_snapshot() {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilterContext context = new MeasureFilterContext();
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setOnBaseResourceChildren(true);
+    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+
+    context.setBaseSnapshot(new SnapshotDto().setId(123L));
+    assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
+  }
+
+  @Test
+  public void filter_is_not_valid_if_condition_on_unknown_metric() {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilterContext context = new MeasureFilterContext();
+    MeasureFilter filter = new MeasureFilter().addCondition(new MeasureFilterCondition(null, MeasureFilterCondition.Operator.LESS, 3.0));
+    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+  }
+
+  @Test
+  public void filter_is_not_valid_if_sorting_on_unknown_metric() {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilterContext context = new MeasureFilterContext();
+    MeasureFilter filter = new MeasureFilter().setSortOnMetric(null);
+    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+  }
+
+  @Test
+  public void filter_is_not_valid_if_anonymous_favourites() {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilterContext context = new MeasureFilterContext();
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setUserFavourites(true);
+    assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
+
+    context.setUserId(123L);
+    assertThat(MeasureFilterExecutor.isValid(filter, context)).isTrue();
+  }
+
+  @Test
+  public void projects_without_measure_conditions() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);
+    verifyJavaProject(rows.get(0));
+    verifyPhpProject(rows.get(1));
+  }
+
+  @Test
+  public void should_prevent_sql_injection_through_parameters() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter()
+      .setResourceQualifiers(Arrays.asList("'"))
+      .setBaseResourceKey("'")
+      .setResourceKey("'")
+      .setResourceName("'")
+      .setResourceName("'")
+      .setResourceScopes(Arrays.asList("'"));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+    // an exception would be thrown if SQL is not valid
+    assertThat(rows).isEmpty();
+  }
+
+  @Test
+  public void test_default_sort() {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"));
+
+    assertThat(filter.sort().isAsc()).isTrue();
+    assertThat(filter.sort().field()).isEqualTo(MeasureFilterSort.Field.NAME);
+    assertThat(filter.sort().metric()).isNull();
+  }
+
+  @Test
+  public void sort_by_ascending_resource_name() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Big -> Tiny
+    assertThat(rows).hasSize(2);
+    verifyJavaBigFile(rows.get(0));
+    verifyJavaTinyFile(rows.get(1));
+  }
+
+  @Test
+  public void sort_by_ascending_resource_key() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.KEY);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Big -> Tiny
+    assertThat(rows).hasSize(2);
+    verifyJavaBigFile(rows.get(0));
+    verifyJavaTinyFile(rows.get(1));
+  }
+
+  @Test
+  public void sort_by_ascending_resource_version() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.VERSION);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Java Project 1.0 then Php Project 3.0
+    assertThat(rows).hasSize(2);
+    verifyJavaProject(rows.get(0));
+    verifyPhpProject(rows.get(1));
+  }
+
+  @Test
+  public void sort_by_descending_resource_name() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Tiny -> Big
+    assertThat(rows).hasSize(2);
+    verifyJavaTinyFile(rows.get(0));
+    verifyJavaBigFile(rows.get(1));
+  }
+
+  @Test
+  public void sort_by_ascending_text_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);
+    verifyPhpProject(rows.get(0));//php way
+    verifyJavaProject(rows.get(1));// Sonar way
+  }
+
+  @Test
+  public void sort_by_descending_text_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);
+    verifyJavaProject(rows.get(0));// Sonar way
+    verifyPhpProject(rows.get(1));//php way
+  }
+
+  @Test
+  public void sort_by_missing_text_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    // the metric 'profile' is not set on files
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_PROFILE);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);//2 files randomly sorted
+  }
+
+  @Test
+  public void sort_by_ascending_numeric_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Tiny -> Big
+    assertThat(rows).hasSize(2);
+    verifyJavaTinyFile(rows.get(0));
+    verifyJavaBigFile(rows.get(1));
+  }
+
+  @Test
+  public void sort_by_descending_numeric_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Big -> Tiny
+    assertThat(rows).hasSize(2);
+    verifyJavaBigFile(rows.get(0));
+    verifyJavaTinyFile(rows.get(1));
+  }
+
+  @Test
+  public void null_measures_are_ordered_after_descending_numeric_measures() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+      .setSortOnMetric(METRIC_COVERAGE).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Java project has coverage but not PHP
+    assertThat(rows).hasSize(2);
+    verifyJavaProject(rows.get(0));
+    verifyPhpProject(rows.get(1));
+  }
+
+  @Test
+  public void null_measures_are_ordered_after_ascending_numeric_measures() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+      .setSortOnMetric(METRIC_COVERAGE).setSortAsc(true);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Java project has coverage but not PHP
+    assertThat(rows).hasSize(2);
+    verifyJavaProject(rows.get(0));
+    verifyPhpProject(rows.get(1));
+  }
+
+  @Test
+  public void sort_by_missing_numeric_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    // coverage measures are not computed
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_UNKNOWN);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // 2 files, random order
+    assertThat(rows).hasSize(2);
+  }
+
+  @Test
+  public void sort_by_ascending_variation() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_LINES).setSortOnPeriod(5);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);
+    verifyJavaProject(rows.get(0));// +400
+    verifyPhpProject(rows.get(1));// +4900
+  }
+
+  @Test
+  public void sort_by_descending_variation() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+      .setSortOnMetric(METRIC_LINES).setSortOnPeriod(5).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);
+    verifyPhpProject(rows.get(0));// +4900
+    verifyJavaProject(rows.get(1));// +400
+  }
+
+  @Test
+  public void sort_by_ascending_date() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    verifyJavaProject(rows.get(0));// 2008
+    verifyPhpProject(rows.get(1));// 2012
+  }
+
+  @Test
+  public void sort_by_descending_date() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.DATE).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    verifyPhpProject(rows.get(0));// 2012
+    verifyJavaProject(rows.get(1));// 2008
+  }
+
+  @Test
+  public void sort_by_ascending_created_at() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    verifyJavaProject(rows.get(0));// 2008
+    assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2008-12-19");
+    verifyPhpProject(rows.get(1));// 2012
+    assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2012-12-12");
+  }
+
+  @Test
+  public void sort_by_descending_created_at() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.PROJECT_CREATION_DATE).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    verifyPhpProject(rows.get(0));// 2012
+    assertThat(DateUtils.formatDate(rows.get(0).getSortDate())).isEqualTo("2012-12-12");
+    verifyJavaProject(rows.get(1));// 2008
+    assertThat(DateUtils.formatDate(rows.get(1).getSortDate())).isEqualTo("2008-12-19");
+  }
+
+  @Test
+  public void sort_by_ascending_alert() throws SQLException {
+    db.prepareDbUnit(getClass(), "sort_by_alert.xml");
+
+    Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Php Project OK, Java Project WARN then Js Project ERROR
+    assertThat(rows).hasSize(3);
+    verifyPhpProject(rows.get(0));
+    verifyJavaProject(rows.get(1));
+    verifyProject(rows.get(2), 120L, 20L, 20L);
+  }
+
+  @Test
+  public void sort_by_descending_alert() throws SQLException {
+    db.prepareDbUnit(getClass(), "sort_by_alert.xml");
+
+    Metric alert = new Metric.Builder(CoreMetrics.ALERT_STATUS_KEY, "Alert", Metric.ValueType.LEVEL).create().setId(5);
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(alert).setSortAsc(false);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // Js Project ERROR, Java Project WARN, then Php Project OK
+    assertThat(rows).hasSize(3);
+    verifyProject(rows.get(0), 120L, 20L, 20L);
+    verifyJavaProject(rows.get(1));
+    verifyPhpProject(rows.get(2));
+  }
+
+  @Test
+  public void condition_on_numeric_measure() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
+      .setSortOnMetric(METRIC_LINES)
+      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 200));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);
+    verifyJavaBigFile(rows.get(0));
+  }
+
+  @Test
+  public void condition_on_measure_variation() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+      .setSortOnMetric(METRIC_LINES)
+      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 1000).setPeriod(5));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);
+    verifyPhpProject(rows.get(0));
+  }
+
+  @Test
+  public void multiple_conditions_on_numeric_measures() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
+      .setSortOnMetric(METRIC_LINES)
+      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.GREATER, 2))
+      .addCondition(new MeasureFilterCondition(METRIC_LINES, MeasureFilterCondition.Operator.LESS_OR_EQUALS, 50));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);
+    verifyJavaTinyFile(rows.get(0));
+  }
+
+  @Test
+  public void filter_by_min_date() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setFromDate(DateUtils.parseDate("2012-12-13"));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
+    assertThat(rows).hasSize(1);
+    verifyPhpProject(rows.get(0));
+  }
+
+  @Test
+  public void filter_by_range_of_dates() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
+      .setFromDate(DateUtils.parseDate("2007-01-01"))
+      .setToDate(DateUtils.parseDate("2010-01-01"));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    // php has been analyzed in 2012-12-13, whereas java project has been analyzed in 2008
+    assertThat(rows).hasSize(1);
+    verifyJavaProject(rows.get(0));
+  }
+
+  @Test
+  public void filter_by_component_name() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceName("PHP Proj");
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);
+    verifyPhpProject(rows.get(0));
+  }
+
+  @Test
+  public void filter_by_component_key() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceKey("Va_proje");
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);
+    verifyJavaProject(rows.get(0));
+  }
+
+  /**
+   * see SONAR-4195
+   */
+  @Test
+  public void filter_by_upper_case_component_key() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setResourceKey("big");
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);
+    verifyJavaBigFile(rows.get(0));
+  }
+
+  /**
+   * see SONAR-4796
+   */
+  @Test
+  public void escape_percent_and_underscore_when_filter_by_component_name_or_key() throws SQLException {
+    db.prepareDbUnit(getClass(), "escape_percent_and_underscore_when_filter_by_component_name_or_key.xml");
+
+    assertThat(executor.execute(
+      new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceKey("java_"),
+      new MeasureFilterContext())).hasSize(2);
+
+    assertThat(executor.execute(
+      new MeasureFilter().setResourceQualifiers(newArrayList("CLA")).setResourceName("java%"),
+      new MeasureFilterContext())).hasSize(2);
+  }
+
+  @Test
+  public void filter_by_base_resource() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setBaseResourceKey("java_project");
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(2);
+    // default sort is on resource name
+    verifyJavaBigFile(rows.get(0));
+    verifyJavaTinyFile(rows.get(1));
+  }
+
+  @Test
+  public void filter_by_parent_resource() throws SQLException {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setBaseResourceKey("java_project").setOnBaseResourceChildren(true);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).hasSize(1);// the package org.sonar.foo
+    assertThat(rows.get(0).getSnapshotId()).isEqualTo(JAVA_PACKAGE_SNAPSHOT_ID);
+  }
+
+  @Test
+  public void filter_by_parent_without_children() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "PAC", "CLA")).setBaseResourceKey("java_project:org.sonar.foo.Big").setOnBaseResourceChildren(true);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
+
+    assertThat(rows).isEmpty();
+  }
+
+  @Test
+  public void filter_by_user_favourites() throws Exception {
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK", "FIL")).setUserFavourites(true);
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+    assertThat(rows).hasSize(2);
+    verifyJavaBigFile(rows.get(0));
+    verifyPhpProject(rows.get(1));
+  }
+
+  @Test
+  public void ignore_person_measures_in_condition() throws Exception {
+    db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
+      new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
+    );
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+    assertThat(rows).hasSize(1);
+    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+  }
+
+  @Test
+  public void ignore_person_measures_in_sort() throws Exception {
+    db.prepareDbUnit(getClass(), "ignore_person_measures.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+    assertThat(rows).hasSize(1);
+    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+  }
+
+  @Test
+  public void ignore_quality_model_measures_in_condition() throws Exception {
+    db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).addCondition(
+      new MeasureFilterCondition(new Metric("ncloc").setId(1), MeasureFilterCondition.Operator.GREATER, 0.0)
+    );
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+    assertThat(rows).hasSize(1);
+    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+  }
+
+  @Test
+  public void ignore_quality_model_measures_in_sort() throws Exception {
+    db.prepareDbUnit(getClass(), "ignore_quality_model_measures.xml");
+    MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(new Metric("ncloc").setId(1));
+    List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext().setUserId(50L));
+
+    assertThat(rows).hasSize(1);
+    assertThat(rows.get(0).getSnapshotId()).isEqualTo(101L);
+  }
+
+
+  private void verifyJavaProject(MeasureFilterRow row) {
+    verifyProject(row, JAVA_PROJECT_SNAPSHOT_ID, JAVA_PROJECT_ID, JAVA_PROJECT_ID);
+  }
+
+  private void verifyJavaBigFile(MeasureFilterRow row) {
+    verifyProject(row, JAVA_FILE_BIG_SNAPSHOT_ID, JAVA_FILE_BIG_ID, JAVA_PROJECT_ID);
+  }
+
+  private void verifyJavaTinyFile(MeasureFilterRow row) {
+    verifyProject(row, JAVA_FILE_TINY_SNAPSHOT_ID, JAVA_FILE_TINY_ID, JAVA_PROJECT_ID);
+  }
+
+  private void verifyPhpProject(MeasureFilterRow row) {
+    verifyProject(row, PHP_SNAPSHOT_ID, PHP_PROJECT_ID, PHP_PROJECT_ID);
+  }
+
+  private void verifyProject(MeasureFilterRow row, Long snashotId, Long resourceId, Long resourceRootId) {
+    assertThat(row.getSnapshotId()).isEqualTo(snashotId);
+    assertThat(row.getResourceId()).isEqualTo(resourceId);
+    assertThat(row.getResourceRootId()).isEqualTo(resourceRootId);
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterFactoryTest.java b/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterFactoryTest.java
new file mode 100644 (file)
index 0000000..bd6348e
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * 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.measure;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class MeasureFilterFactoryTest {
+
+  System2 system = mock(System2.class);
+
+  @Test
+  public void sort_on_measure_value() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc");
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(filter.sort().column()).isEqualTo("pmsort.value");
+    assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
+    assertThat(filter.sort().period()).isNull();
+  }
+
+  @Test
+  public void sort_on_measure_variation() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:ncloc:3");
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(filter.sort().column()).isEqualTo("pmsort.variation_value_3");
+    assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc");
+    assertThat(filter.sort().period()).isEqualTo(3);
+  }
+
+  @Test
+  public void sort_on_name() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "name");
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(filter.sort().column()).isEqualTo("p.long_name");
+    assertThat(filter.sort().metric()).isNull();
+    assertThat(filter.sort().period()).isNull();
+  }
+
+  @Test
+  public void fallback_on_name_sort_when_metric_is_unknown() {
+    MetricFinder finder = mock(MetricFinder.class);
+    when(finder.findByKey(anyString())).thenReturn(null);
+    MeasureFilterFactory factory = new MeasureFilterFactory(finder, system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of("sort", "metric:sqale_index");
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(filter.sort().column()).isEqualTo("p.long_name");
+    assertThat(filter.sort().metric()).isNull();
+    assertThat(filter.sort().period()).isNull();
+    assertThat(filter.sort().isAsc()).isTrue();
+  }
+
+  @Test
+  public void descending_sort() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of("asc", "false");
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(filter.sort().column()).isEqualTo("p.long_name");
+    assertThat(filter.sort().metric()).isNull();
+    assertThat(filter.sort().period()).isNull();
+    assertThat(filter.sort().isAsc()).isFalse();
+  }
+
+  @Test
+  public void ascending_sort_by_default() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = Maps.newHashMap();
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(filter.sort().column()).isEqualTo("p.long_name");
+    assertThat(filter.sort().metric()).isNull();
+    assertThat(filter.sort().period()).isNull();
+    assertThat(filter.sort().isAsc()).isTrue();
+  }
+
+  @Test
+  public void date_conditions() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of(
+      "fromDate", "2012-01-25",
+      "toDate", "2012-02-18"
+    );
+    MeasureFilter filter = factory.create(props);
+
+    assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2012-01-25");
+    assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2012-02-18");
+  }
+
+  @Test
+  public void age_conditions() {
+    long today = DateUtils.parseDateTime("2013-05-18T11:00:00+0000").getTime();
+    when(system.now()).thenReturn(today);
+
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of(
+      "ageMaxDays", "3",
+      "ageMinDays", "1"
+    );
+    MeasureFilter filter = factory.create(props);
+    assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2013-05-15");
+    assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2013-05-17");
+  }
+
+  @Test
+  public void measure_value_condition() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of(
+      "c1_metric", "complexity",
+      "c1_op", "gte",
+      "c1_val", "3.14"
+    );
+    MeasureFilter filter = factory.create(props);
+
+    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+    assertThat(conditions).hasSize(1);
+    assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
+    assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
+    assertThat(conditions.get(0).value()).isEqualTo(3.14);
+    assertThat(conditions.get(0).period()).isNull();
+  }
+
+  @Test
+  public void measure_variation_condition() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of(
+      "c1_metric", "complexity",
+      "c1_op", "gte",
+      "c1_val", "3.14",
+      "c1_period", "3"
+    );
+    MeasureFilter filter = factory.create(props);
+
+    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+    assertThat(conditions).hasSize(1);
+    assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity");
+    assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS);
+    assertThat(conditions.get(0).value()).isEqualTo(3.14);
+    assertThat(conditions.get(0).period()).isEqualTo(3);
+  }
+
+  @Test
+  public void alert_level_condition() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of(
+      "alertLevels", Arrays.asList("error", "warn")
+    );
+    MeasureFilter filter = factory.create(props);
+
+    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+    assertThat(conditions).hasSize(1);
+    assertThat(conditions.get(0).metric().getKey()).isEqualTo("alert_status");
+    assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.IN);
+    assertThat(conditions.get(0).value()).isEqualTo(0);
+    assertThat(conditions.get(0).textValue()).isEqualTo("('ERROR', 'WARN')");
+    assertThat(conditions.get(0).period()).isNull();
+  }
+
+  @Test
+  public void ignore_partial_measure_condition() {
+    MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder(), system);
+    Map<String, Object> props = ImmutableMap.<String, Object>of(
+      "c1_op", "gte",
+      "c1_val", "3.14"
+    );
+    MeasureFilter filter = factory.create(props);
+
+    List<MeasureFilterCondition> conditions = filter.getMeasureConditions();
+    assertThat(conditions).isEmpty();
+  }
+
+  private MetricFinder newMetricFinder() {
+    MetricFinder finder = mock(MetricFinder.class);
+    when(finder.findByKey(anyString())).thenAnswer(new Answer<Metric>() {
+      public Metric answer(InvocationOnMock invocationOnMock) throws Throwable {
+        String key = (String) invocationOnMock.getArguments()[0];
+        return new Metric.Builder(key, key, Metric.ValueType.INT).create();
+      }
+    });
+    return finder;
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterTest.java b/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterTest.java
new file mode 100644 (file)
index 0000000..89469a1
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.measure;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MeasureFilterTest {
+  @Test
+  public void should_sanitize_list() {
+    assertThat(MeasureFilter.sanitize(null)).isEmpty();
+    assertThat(MeasureFilter.sanitize(Lists.<String>newArrayList())).isEmpty();
+    assertThat(MeasureFilter.sanitize(Arrays.asList(""))).isEmpty();
+    assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK"))).containsExactly("TRK");
+    assertThat(MeasureFilter.sanitize(Lists.newArrayList("TRK", "BRC"))).containsExactly("TRK", "BRC");
+  }
+
+  @Test
+  public void filter_is_not_empty_if_at_least_condition_on_favourites() {
+    assertThat(new MeasureFilter().isEmpty()).isTrue();
+    assertThat(new MeasureFilter().setUserFavourites(true).isEmpty()).isFalse();
+  }
+
+  @Test
+  public void filter_is_not_empty_if_at_least_condition_on_qualifiers() {
+    assertThat(new MeasureFilter().isEmpty()).isTrue();
+    assertThat(new MeasureFilter().setResourceQualifiers(Collections.<String>emptyList()).isEmpty()).isTrue();
+    assertThat(new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).isEmpty()).isFalse();
+  }
+
+  @Test
+  public void filter_is_not_empty_if_at_least_condition_on_scopes() {
+    assertThat(new MeasureFilter().isEmpty()).isTrue();
+    assertThat(new MeasureFilter().setResourceScopes(Collections.<String>emptyList()).isEmpty()).isTrue();
+    assertThat(new MeasureFilter().setResourceScopes(Arrays.asList("PRJ")).isEmpty()).isFalse();
+  }
+
+  @Test
+  public void filter_is_not_empty_if_at_least_condition_on_root_resource() {
+    assertThat(new MeasureFilter().isEmpty()).isTrue();
+    assertThat(new MeasureFilter().setBaseResourceKey("foo").isEmpty()).isFalse();
+  }
+}
diff --git a/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/escape_percent_and_underscore_when_filter_by_component_name_or_key.xml b/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/escape_percent_and_underscore_when_filter_by_component_name_or_key.xml
new file mode 100644 (file)
index 0000000..2419fb9
--- /dev/null
@@ -0,0 +1,67 @@
+<dataset>
+
+  <!-- java project -->
+  <projects kee="java_project:org.sonar.bar" long_name="org.sonar.bar" scope="FIL" qualifier="CLA" name="org.sonar.bar"
+            id="1" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <projects kee="java_project:org.sonar.foo" scope="FIL" qualifier="CLA" long_name="org.sonar.foo" name="org.sonar.foo"
+            id="2" root_id="1"
+            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <projects kee="java project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
+            name="Big"
+            id="3" root_id="1"
+            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <projects kee="java project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
+            id="4" root_id="1"
+            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="FIL" qualifier="CLA" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
+             scope="FIL" qualifier="CLA" path="101." depth="1"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+             scope="FIL" qualifier="CLA" path="101.102." depth="2"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+             scope="FIL" qualifier="CLA" path="101.102." depth="2"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <resource_index id="1" kee="java class1" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="CLA"/>
+  <resource_index id="2" kee="java class2" position="1" name_size="12" resource_id="2" root_project_id="1" qualifier="CLA"/>
+  <resource_index id="3" kee="java%class3" position="2" name_size="12" resource_id="3" root_project_id="1" qualifier="CLA"/>
+  <resource_index id="4" kee="java%class4" position="3" name_size="12" resource_id="4" root_project_id="1" qualifier="CLA"/>
+
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/ignore_person_measures.xml b/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/ignore_person_measures.xml
new file mode 100644 (file)
index 0000000..c868a8d
--- /dev/null
@@ -0,0 +1,44 @@
+<dataset>
+  <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
+           short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
+           optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
+           delete_historical_data="[null]"/>
+
+  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+            id="1" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
+
+  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+
+  <!-- standard measure -->
+  <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" person_id="[null]"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <!-- details of the measure by person -->
+  <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" person_id="30000"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" person_id="40000"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/ignore_quality_model_measures.xml b/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/ignore_quality_model_measures.xml
new file mode 100644 (file)
index 0000000..6289fa9
--- /dev/null
@@ -0,0 +1,44 @@
+<dataset>
+  <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
+           short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
+           optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
+           delete_historical_data="[null]"/>
+
+  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+            id="1" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
+
+  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+
+  <!-- standard measure -->
+  <project_measures id="1001" metric_id="1" value="500" snapshot_id="101" characteristic_id="[null]"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" person_id="[null]"/>
+
+  <!-- details of the measure by model characteristic -->
+  <project_measures id="1002" metric_id="1" value="300" snapshot_id="101" characteristic_id="30000"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" person_id="[null]"/>
+
+  <project_measures id="1003" metric_id="1" value="200" snapshot_id="101" characteristic_id="40000"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" person_id="[null]"/>
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/shared.xml
new file mode 100644 (file)
index 0000000..173b39e
--- /dev/null
@@ -0,0 +1,181 @@
+<dataset>
+  <metrics id="1" name="lines" val_type="FLOAT" description="Lines" domain="Size"
+           short_name="Lines" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV" worst_value="[null]"
+           optimized_best_value="[null]" best_value="[null]" direction="1" hidden="[false]"
+           delete_historical_data="[null]"/>
+
+  <metrics id="2" name="profile" val_type="STRING" description="Profile" domain="Rules"
+           short_name="Profile" qualitative="[false]" user_managed="[false]" enabled="[true]" origin="JAV"
+           worst_value="[null]"
+           optimized_best_value="[null]" best_value="[null]" direction="0" hidden="[false]"
+           delete_historical_data="[null]"/>
+
+  <metrics id="3" name="coverage" val_type="FLOAT" description="Coverage" domain="Test"
+           short_name="Coverage" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+           worst_value="[null]"
+           optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
+           delete_historical_data="[null]"/>
+
+  <metrics id="4" name="unknown" val_type="FLOAT" description="Coverage" domain="Test"
+             short_name="Unknown" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+             worst_value="[null]"
+             optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]"
+             delete_historical_data="[null]"/>
+
+  <!-- java project -->
+  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+            id="1" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <projects kee="java_project:org.sonar.foo" scope="DIR" qualifier="PAC" long_name="org.sonar.foo" name="org.sonar.foo"
+            id="2" root_id="1"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <projects kee="java_project:org.sonar.foo.Big" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Big"
+            name="Big"
+            id="3" root_id="1"
+            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <projects kee="java_project:org.sonar.foo.Tiny" scope="FIL" qualifier="CLA" long_name="org.sonar.foo.Tiny" name="Tiny"
+            id="4" root_id="1"
+            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <snapshots id="102" project_id="2" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="101"
+             scope="DIR" qualifier="PAC" path="101." depth="1"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <snapshots id="103" project_id="3" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+             scope="FIL" qualifier="CLA" path="101.102." depth="2"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+  <snapshots id="104" project_id="4" root_project_id="1" root_snapshot_id="101" parent_snapshot_id="102"
+             scope="FIL" qualifier="CLA" path="101.102." depth="2"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+
+  <!-- lines, variation during period 5 -->
+  <project_measures id="1001" metric_id="1" value="510" snapshot_id="101"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <project_measures id="1002" metric_id="1" value="510" snapshot_id="102"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <project_measures id="1003" metric_id="1" value="500" snapshot_id="103"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <project_measures id="1004" metric_id="1" value="10" snapshot_id="104"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <!-- profile of java project -->
+  <project_measures id="1005" metric_id="2" value="[null]" snapshot_id="101"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <!-- coverage of java project -->
+  <project_measures id="1006" metric_id="3" value="12.3" snapshot_id="101"
+                      url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                      variation_value_4="[null]" variation_value_5="[null]"
+                      rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                      RULE_ID="[null]" text_value="Sonar way" tendency="[null]" measure_date="[null]" project_id="[null]"
+                      alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <!-- php project -->
+  <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
+            id="10" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2012-12-12 04:06:00.00"/>
+
+
+  <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
+             version="3.0" status="P" islast="[true]"/>
+
+  <!-- lines, many new lines during period 5 -->
+  <project_measures id="1010" metric_id="1" value="5000" snapshot_id="110"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="4900"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <project_measures id="1011" metric_id="2" value="[null]" snapshot_id="110"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="php way" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+
+  <resource_index id="1" kee="java project" position="0" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+  <resource_index id="2" kee="java projec" position="1" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+  <resource_index id="3" kee="java proje" position="2" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+  <resource_index id="4" kee="java proj" position="3" name_size="12" resource_id="1" root_project_id="1" qualifier="TRK"/>
+  <!-- etc -->
+  <resource_index id="5" kee="php project" position="0" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+  <resource_index id="6" kee="php projec" position="1" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+  <resource_index id="7" kee="php proje" position="2" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+  <resource_index id="8" kee="php proj" position="3" name_size="11" resource_id="10" root_project_id="10" qualifier="TRK"/>
+  <!-- etc -->
+
+
+  <!-- two favourites : Big.java and PHP project -->
+  <properties id="1" prop_key="favourite" resource_id="3" text_value="[null]" user_id="50"/>
+  <properties id="2" prop_key="favourite" resource_id="10" text_value="[null]" user_id="50"/>
+
+  <!-- another properties -->
+  <properties id="3" prop_key="favourite" resource_id="1" text_value="[null]" user_id="1234"/>
+  <properties id="4" prop_key="sonar.profile" resource_id="1" text_value="Sonar way" user_id="[null]"/>
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/sort_by_alert.xml b/sonar-server/src/test/resources/org/sonar/server/measure/MeasureFilterExecutorTest/sort_by_alert.xml
new file mode 100644 (file)
index 0000000..a837664
--- /dev/null
@@ -0,0 +1,81 @@
+<dataset>
+  <metrics id="5" name="alert_status" val_type="LEVEL" description="Alert" domain="General"
+           short_name="Alert" qualitative="[true]" user_managed="[false]" enabled="[true]" origin="JAV"
+           worst_value="[null]"
+           optimized_best_value="[true]" best_value="[null]" direction="1" hidden="[false]"
+           delete_historical_data="[null]"/>
+
+  <!-- java project -->
+  <projects kee="java_project" long_name="Java project" scope="PRJ" qualifier="TRK" name="Java project"
+            id="1" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-19 00:00:00.00"/>
+
+  <snapshots id="101" project_id="1" root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00"
+             version="1.0" status="P" islast="[true]"/>
+
+
+  <!-- alert -->
+  <project_measures id="1001" metric_id="5" value="510" snapshot_id="101"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="400"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="WARN" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <!-- php project -->
+  <projects kee="php_project" long_name="PHP project" scope="PRJ" qualifier="TRK" name="PHP project"
+            id="10" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2012-12-12 04:06:00.00"/>
+
+
+  <snapshots id="110" project_id="10" root_project_id="10" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
+             version="3.0" status="P" islast="[true]"/>
+
+  <!-- alert -->
+  <project_measures id="1010" metric_id="5" value="5000" snapshot_id="110"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="OK" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+  <!-- js project -->
+  <projects kee="js_project" long_name="JS project" scope="PRJ" qualifier="TRK" name="JS project"
+            id="20" root_id="[null]"
+            description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"
+            created_at="2012-12-12 04:06:00.00"/>
+
+
+  <snapshots id="120" project_id="20" root_project_id="20" root_snapshot_id="[null]" parent_snapshot_id="[null]"
+             scope="PRJ" qualifier="TRK" path="" depth="0"
+             purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+             period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+             period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+             period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+             created_at="2012-12-13 04:06:00.00" build_date="2012-12-13 04:06:00.00"
+             version="3.0" status="P" islast="[true]"/>
+
+  <!-- alert -->
+  <project_measures id="1020" metric_id="5" value="5000" snapshot_id="120"
+                    url="[null]" variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]"
+                    variation_value_4="[null]" variation_value_5="[null]"
+                    rule_priority="[null]" alert_text="[null]" RULES_CATEGORY_ID="[null]"
+                    RULE_ID="[null]" text_value="ERROR" tendency="[null]" measure_date="[null]" project_id="[null]"
+                    alert_status="[null]" description="[null]" characteristic_id="[null]"/>
+
+
+</dataset>