*/
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.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.measures.Metric;
-import org.sonar.api.utils.DateUtils;
import javax.annotation.Nullable;
-import java.util.Calendar;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
-import java.util.Map;
public class MeasureFilter {
- private static final String[] EMPTY = {};
// conditions on resources
private String baseResourceKey;
private boolean onBaseResourceChildren = false; // only if getBaseResourceKey is set
- private String[] resourceScopes = EMPTY;
- private String[] resourceQualifiers = EMPTY;
- private String[] resourceLanguages = EMPTY;
+ private List<String> resourceScopes = Collections.emptyList();
+ private List<String> resourceQualifiers = Collections.emptyList();
+ private List<String> resourceLanguages = Collections.emptyList();
private String resourceKeyRegexp;
private String resourceName;
private Date fromDate = null, toDate = null;
return onBaseResourceChildren;
}
- public MeasureFilter setResourceScopes(String... l) {
- this.resourceScopes = (l != null ? l : EMPTY);
+ public MeasureFilter setResourceScopes(@Nullable List<String> list) {
+ this.resourceScopes = sanitize(list);
return this;
}
- public MeasureFilter setResourceQualifiers(String... l) {
- this.resourceQualifiers = l;
+ public MeasureFilter setResourceQualifiers(@Nullable List<String> list) {
+ this.resourceQualifiers = sanitize(list);
return this;
}
- public MeasureFilter setResourceLanguages(String... l) {
- this.resourceLanguages = (l != null ? l : EMPTY);
- return this;
- }
-
- public MeasureFilter setResourceScopes(@Nullable List<String> l) {
- this.resourceScopes = (l != null ? l.toArray(new String[l.size()]) : EMPTY);
- return this;
- }
-
- public MeasureFilter setResourceQualifiers(@Nullable List<String> l) {
- this.resourceQualifiers = (l != null ? l.toArray(new String[l.size()]) : EMPTY);
- return this;
- }
-
- public MeasureFilter setResourceLanguages(@Nullable List<String> l) {
- this.resourceLanguages = (l != null ? l.toArray(new String[l.size()]) : EMPTY);
+ public MeasureFilter setResourceLanguages(@Nullable List<String> list) {
+ this.resourceLanguages = sanitize(list);
return this;
}
return toDate;
}
- public String[] getResourceScopes() {
+ public List<String> getResourceScopes() {
return resourceScopes;
}
- public String[] getResourceQualifiers() {
+ public List<String> getResourceQualifiers() {
return resourceQualifiers;
}
- public String[] getResourceLanguages() {
+ public List<String> getResourceLanguages() {
return resourceLanguages;
}
return sort;
}
- public static MeasureFilter create(Map<String, String> properties) {
- MeasureFilter filter = new MeasureFilter();
- filter.setBaseResourceKey(properties.get("base"));
- filter.setResourceScopes(toArray(properties.get("scopes")));
- filter.setResourceQualifiers(toArray(properties.get("qualifiers")));
- filter.setResourceLanguages(toArray(properties.get("languages")));
- if (properties.containsKey("onBaseChildren")) {
- filter.setOnBaseResourceChildren(Boolean.valueOf(properties.get("onBaseChildren")));
- }
- filter.setResourceName(properties.get("nameRegexp"));
- filter.setResourceKeyRegexp(properties.get("keyRegexp"));
- if (properties.containsKey("fromDate")) {
- filter.setFromDate(toDate(properties.get("fromDate")));
- } else if (properties.containsKey("afterDays")) {
- filter.setFromDate(toDays(properties.get("afterDays")));
- }
- if (properties.containsKey("toDate")) {
- filter.setToDate(toDate(properties.get("toDate")));
- } else if (properties.containsKey("beforeDays")) {
- filter.setToDate(toDays(properties.get("beforeDays")));
- }
-
- if (properties.containsKey("favourites")) {
- filter.setUserFavourites(Boolean.valueOf(properties.get("favourites")));
- }
- return filter;
+ @VisibleForTesting
+ static List<String> sanitize(@Nullable List<String> list) {
+ return isBlank(list) ? Collections.<String>emptyList() : list;
}
- private static String[] toArray(@Nullable String s) {
- if (s == null) {
- return EMPTY;
+ private static boolean isBlank(@Nullable List<String> list) {
+ boolean blank = false;
+ if (list == null || list.isEmpty() || (list.size() == 1 && Strings.isNullOrEmpty(list.get(0)))) {
+ blank = true;
}
- return StringUtils.split(s, ",");
+ return blank;
}
- private static Date toDate(@Nullable String date) {
- if (date != null) {
- return DateUtils.parseDate(date);
- }
- return null;
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
}
-
- private static Date toDays(@Nullable String s) {
- if (s != null) {
- int days = Integer.valueOf(s);
- Date date = org.apache.commons.lang.time.DateUtils.truncate(new Date(), Calendar.DATE);
- date = org.apache.commons.lang.time.DateUtils.addDays(date, -days);
- return date;
- }
- return null;
- }
-
}
*/
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 {
sql.append(metric.getId());
sql.append(" AND ").append(valueColumn()).append(operator).append(value);
}
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
+ }
}
package org.sonar.core.measure;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Maps;
+import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.SystemUtils;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
private static final Logger FILTER_LOG = LoggerFactory.getLogger("org.sonar.MEASURE_FILTER");
private final MeasureFilterDecoder decoder;
+ private final MeasureFilterFactory factory;
private final MeasureFilterExecutor executor;
- public MeasureFilterEngine(MeasureFilterDecoder decoder, MeasureFilterExecutor executor) {
+ public MeasureFilterEngine(MeasureFilterDecoder decoder, MeasureFilterFactory factory, MeasureFilterExecutor executor) {
this.decoder = decoder;
this.executor = executor;
+ this.factory = factory;
}
public List<MeasureFilterRow> execute(String filterJson, @Nullable Long userId) throws ParseException {
return execute(filterJson, userId, FILTER_LOG);
}
- public List<MeasureFilterRow> execute2(Map<String, String> filterMap, @Nullable Long userId) throws ParseException {
+ public List<MeasureFilterRow> execute2(Map<String, Object> filterMap, @Nullable Long userId) throws ParseException {
Logger logger = FILTER_LOG;
MeasureFilterContext context = new MeasureFilterContext();
- context.setJson(filterMap.toString());
+ context.setJson(Joiner.on("|").withKeyValueSeparator("=").join(filterMap));
context.setUserId(userId);
try {
long start = System.currentTimeMillis();
- MeasureFilter filter = MeasureFilter.create(filterMap);
+ MeasureFilter filter = factory.create(filterMap);
List<MeasureFilterRow> rows = executor.execute(filter, context);
log(context, rows, (System.currentTimeMillis() - start), logger);
return rows;
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.core.measure;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.utils.DateUtils;
+
+import javax.annotation.Nullable;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class MeasureFilterFactory implements ServerComponent {
+
+ private MetricFinder metricFinder;
+
+ public MeasureFilterFactory(MetricFinder metricFinder) {
+ this.metricFinder = metricFinder;
+ }
+
+ public MeasureFilter create(Map<String, Object> properties) {
+ MeasureFilter filter = new MeasureFilter();
+ filter.setBaseResourceKey((String)properties.get("base"));
+ filter.setResourceScopes((List<String>)properties.get("scopes"));
+ filter.setResourceQualifiers((List<String>)(properties.get("qualifiers")));
+ filter.setResourceLanguages((List<String>)(properties.get("languages")));
+ if (properties.containsKey("onBaseChildren")) {
+ filter.setOnBaseResourceChildren(Boolean.valueOf((String)properties.get("onBaseChildren")));
+ }
+ filter.setResourceName((String)properties.get("nameRegexp"));
+ filter.setResourceKeyRegexp((String)properties.get("keyRegexp"));
+ if (properties.containsKey("fromDate")) {
+ filter.setFromDate(toDate((String)properties.get("fromDate")));
+ } else if (properties.containsKey("afterDays")) {
+ filter.setFromDate(toDays((String)properties.get("afterDays")));
+ }
+ if (properties.containsKey("toDate")) {
+ filter.setToDate(toDate((String)properties.get("toDate")));
+ } else if (properties.containsKey("beforeDays")) {
+ filter.setToDate(toDays((String)properties.get("beforeDays")));
+ }
+
+ if (properties.containsKey("favourites")) {
+ filter.setUserFavourites(Boolean.valueOf((String)properties.get("favourites")));
+ }
+ if (properties.containsKey("asc")) {
+ filter.setSortAsc(Boolean.valueOf((String)properties.get("asc")));
+ }
+ String s = (String)properties.get("sort");
+ if (s != null) {
+ if (StringUtils.startsWith(s, "metric:")) {
+ filter.setSortOnMetric(metricFinder.findByKey(StringUtils.substringAfter(s, "metric:")));
+ } else {
+ filter.setSortOn(MeasureFilterSort.Field.valueOf(s.toUpperCase()));
+ }
+ }
+// if (map.containsKey("sortPeriod")) {
+// filter.setSortOnPeriod(((Long) map.get("sortPeriod")).intValue());
+// }
+ return filter;
+ }
+
+ private static Date toDate(@Nullable String date) {
+ if (date != null) {
+ return DateUtils.parseDate(date);
+ }
+ return null;
+ }
+
+ private static Date toDays(@Nullable String s) {
+ if (s != null) {
+ int days = Integer.valueOf(s);
+ Date date = org.apache.commons.lang.time.DateUtils.truncate(new Date(), Calendar.DATE);
+ date = org.apache.commons.lang.time.DateUtils.addDays(date, -days);
+ return date;
+ }
+ return null;
+ }
+
+}
if (context.getBaseSnapshot() == null) {
sql.append(" AND p.copy_resource_id IS NULL ");
}
- if (filter.getResourceQualifiers().length > 0) {
+ if (!filter.getResourceQualifiers().isEmpty()) {
sql.append(" AND s.qualifier IN ");
appendInStatement(filter.getResourceQualifiers(), sql);
}
- if (filter.getResourceScopes().length > 0) {
+ if (!filter.getResourceScopes().isEmpty()) {
sql.append(" AND s.scope IN ");
appendInStatement(filter.getResourceScopes(), sql);
}
- if (filter.getResourceLanguages().length > 0) {
+ if (!filter.getResourceLanguages().isEmpty()) {
sql.append(" AND p.language IN ");
appendInStatement(filter.getResourceLanguages(), sql);
}
sql.append(" AND s.project_id IN (SELECT rindex.resource_id FROM resource_index rindex WHERE rindex.kee like '");
sql.append(StringEscapeUtils.escapeSql(StringUtils.lowerCase(filter.getResourceName())));
sql.append("%'");
- if (filter.getResourceQualifiers().length > 0) {
+ if (!filter.getResourceQualifiers().isEmpty()) {
sql.append(" AND rindex.qualifier IN ");
appendInStatement(filter.getResourceQualifiers(), sql);
}
}
- private static void appendInStatement(String[] values, StringBuilder to) {
+ private static void appendInStatement(List<String> values, StringBuilder to) {
to.append(" ('");
to.append(StringUtils.join(values, "','"));
to.append("') ");
Logger logger = mock(Logger.class);
when(logger.isDebugEnabled()).thenReturn(true);
- MeasureFilterEngine engine = new MeasureFilterEngine(decoder, executor);
+ MeasureFilterEngine engine = new MeasureFilterEngine(decoder, null, executor);
final long userId = 50L;
engine.execute("{}", userId, logger);
when(decoder.decode("<xml>")).thenThrow(new ParseException(0));
MeasureFilterExecutor executor = mock(MeasureFilterExecutor.class);
- MeasureFilterEngine engine = new MeasureFilterEngine(decoder, executor);
+ MeasureFilterEngine engine = new MeasureFilterEngine(decoder, null, executor);
engine.execute("<xml>", 50L);
}
}
import org.sonar.core.resource.SnapshotDto;
import java.sql.SQLException;
+import java.util.Arrays;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
@Test
public void filter_is_not_valid_if_missing_base_snapshot() {
MeasureFilterContext context = new MeasureFilterContext();
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setOnBaseResourceChildren(true);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setOnBaseResourceChildren(true);
assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
context.setBaseSnapshot(new SnapshotDto().setId(123L));
@Test
public void filter_is_not_valid_if_anonymous_favourites() {
MeasureFilterContext context = new MeasureFilterContext();
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setUserFavourites(true);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setUserFavourites(true);
assertThat(MeasureFilterExecutor.isValid(filter, context)).isFalse();
context.setUserId(123L);
@Test
public void projects_without_measure_conditions() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortOn(MeasureFilterSort.Field.LANGUAGE);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOn(MeasureFilterSort.Field.LANGUAGE);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(2);
@Test
public void test_default_sort() {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"));
assertThat(filter.sort().isAsc()).isTrue();
assertThat(filter.sort().field()).isEqualTo(MeasureFilterSort.Field.NAME);
@Test
public void sort_by_ascending_resource_name() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortAsc(true);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// Big -> Tiny
@Test
public void sort_by_ascending_resource_key() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortAsc(true).setSortOn(MeasureFilterSort.Field.KEY);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(true).setSortOn(MeasureFilterSort.Field.KEY);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// Big -> Tiny
@Test
public void sort_by_ascending_resource_version() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortAsc(true).setSortOn(MeasureFilterSort.Field.VERSION);
+ 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
@Test
public void sort_by_descending_resource_name() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortAsc(false);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortAsc(false);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// Tiny -> Big
@Test
public void sort_by_ascending_text_measure() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortOnMetric(METRIC_PROFILE);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setSortOnMetric(METRIC_PROFILE);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(2);
@Test
public void sort_by_descending_text_measure() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortOnMetric(METRIC_PROFILE).setSortAsc(false);
+ 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);
@Test
public void sort_by_missing_text_measure() throws SQLException {
// the metric 'profile' is not set on files
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortOnMetric(METRIC_PROFILE);
+ 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 {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortOnMetric(METRIC_LINES);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// Tiny -> Big
@Test
public void sort_by_descending_numeric_measure() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortOnMetric(METRIC_LINES).setSortAsc(false);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_LINES).setSortAsc(false);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// Big -> Tiny
@Test
public void sort_by_missing_numeric_measure() throws SQLException {
// coverage measures are not computed
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setSortOnMetric(METRIC_COVERAGE);
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setSortOnMetric(METRIC_COVERAGE);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
// 2 files, random order
@Test
public void sort_by_ascending_variation() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortOnMetric(METRIC_LINES).setSortOnPeriod(5);
+ 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);
@Test
public void sort_by_descending_variation() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK")
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
.setSortOnMetric(METRIC_LINES).setSortOnPeriod(5).setSortAsc(false);
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
@Test
public void sort_by_ascending_date() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortOn(MeasureFilterSort.Field.DATE);
+ 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
@Test
public void sort_by_descending_date() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setSortOn(MeasureFilterSort.Field.DATE).setSortAsc(false);
+ 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
@Test
public void condition_on_numeric_measure() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA")
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
.setSortOnMetric(METRIC_LINES)
.addCondition(new MeasureFilterCondition(METRIC_LINES, ">", 200));
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
@Test
public void condition_on_measure_variation() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK")
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK"))
.setSortOnMetric(METRIC_LINES)
.addCondition(new MeasureFilterCondition(METRIC_LINES, ">", 1000).setPeriod(5));
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
@Test
public void multiple_conditions_on_numeric_measures() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA")
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA"))
.setSortOnMetric(METRIC_LINES)
.addCondition(new MeasureFilterCondition(METRIC_LINES, ">", 2))
.addCondition(new MeasureFilterCondition(METRIC_LINES, "<=", 50));
@Test
public void filter_by_language() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setResourceLanguages("java", "cobol");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceLanguages(Arrays.asList("java", "cobol"));
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(1);
@Test
public void filter_by_min_date() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setFromDate(DateUtils.parseDate("2012-12-13"));
+ 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
@Test
public void filter_by_range_of_dates() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK")
+ 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());
@Test
public void filter_by_resource_name() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setResourceName("PHP Proj");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceName("PHP Proj");
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(1);
@Test
public void filter_by_resource_key_star_regexp() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setResourceKeyRegexp("java*");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceKeyRegexp("java*");
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(1);
@Test
public void filter_by_resource_key_exclamation_mark() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK").setResourceKeyRegexp("JaV?_proje*");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("TRK")).setResourceKeyRegexp("JaV?_proje*");
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(1);
verifyJavaProject(rows.get(0));
@Test
public void filter_by_base_resource() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("CLA").setBaseResourceKey("java_project");
+ MeasureFilter filter = new MeasureFilter().setResourceQualifiers(Arrays.asList("CLA")).setBaseResourceKey("java_project");
List<MeasureFilterRow> rows = executor.execute(filter, new MeasureFilterContext());
assertThat(rows).hasSize(2);
@Test
public void filter_by_parent_without_children() throws SQLException {
- MeasureFilter filter = new MeasureFilter().setResourceQualifiers("TRK", "PAC", "CLA").setBaseResourceKey("java_project:org.sonar.foo.Big").setOnBaseResourceChildren(true);
+ 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();
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.core.measure;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+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");
+ }
+}
import org.sonar.core.measure.MeasureFilterDecoder;
import org.sonar.core.measure.MeasureFilterEngine;
import org.sonar.core.measure.MeasureFilterExecutor;
+import org.sonar.core.measure.MeasureFilterFactory;
import org.sonar.core.metric.DefaultMetricFinder;
import org.sonar.core.notification.DefaultNotificationManager;
import org.sonar.core.persistence.DaoUtils;
servicesContainer.addSingleton(SettingsChangeNotifier.class);
servicesContainer.addSingleton(PageDecorations.class);
servicesContainer.addSingleton(MeasureFilterDecoder.class);
+ servicesContainer.addSingleton(MeasureFilterFactory.class);
servicesContainer.addSingleton(MeasureFilterExecutor.class);
servicesContainer.addSingleton(MeasureFilterEngine.class);
servicesContainer.addSingleton(DryRunDatabaseFactory.class);
return get(MeasureFilterEngine.class).execute(json, userId);
}
- public List<MeasureFilterRow> executeMeasureFilter2(Map<String,String> map, @Nullable Long userId) throws ParseException {
+ public List<MeasureFilterRow> executeMeasureFilter2(Map<String,Object> map, @Nullable Long userId) throws ParseException {
return get(MeasureFilterEngine.class).execute2(map, userId);
}
else
current_user.add_favourite(favourite_id)
@style='fav'
- @tooltip='Click to delete from favourites'
+ @tooltip='Click to remove from favourites'
end
star_id=params[:elt]
page.element.addClassName(star_id, @style)
page.element.writeAttribute(star_id, 'alt', @tooltip)
page.element.writeAttribute(star_id, 'title', @tooltip)
- end
+ end
end
end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2012 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar 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.
+#
+# Sonar 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 Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+module MeasuresHelper
+
+ def list_column_title(filter, column, url_params)
+ if column.sort?
+ html = link_to(h(column.display_name), url_params.merge({:controller => 'measures', :action => 'search', :asc => (!filter.sort_asc?).to_s, :sort => column.key}))
+ else
+ html=h(column.display_name)
+ end
+ #if column.variation
+ # html="<img src='#{ApplicationController.root_context}/images/trend-up.png'></img> #{html}"
+ #end
+
+ if filter.sort_key==column.key
+ html << (filter.sort_asc? ? image_tag("asc12.png") : image_tag("desc12.png"))
+ end
+ "<th class='#{column.align}'>#{html}</th>"
+ end
+
+end
# Column to be displayed
class Column
- attr_reader :key
+ attr_reader :key, :metric
def initialize(key)
@key = key
- end
-
- def metric
- @metric ||=
- begin
- metric_key = @key.split(':')[1]
- Metric.by_key(metric_key) if metric_key
- end
+ metric_key = @key.split(':')[1]
+ @metric = Metric.by_key(metric_key) if metric_key
end
def display_name
- if metric
- Api::Utils.message("metric.#{metric.key}.name", :default => metric.short_name)
+ if @metric
+ Api::Utils.message("metric.#{@metric.key}.name", :default => @metric.short_name)
else
Api::Utils.message("filters.col.#{@key}", :default => @key)
end
user = options[:user]
rows=Api::Utils.java_facade.executeMeasureFilter2(@criteria, (user ? user.id : nil))
snapshot_ids = filter_authorized_snapshot_ids(rows, controller)
- snapshot_ids = paginate_snapshot_ids(snapshot_ids)
init_data(snapshot_ids)
self
end
def set_criteria_default_value(key, value)
- if !@criteria.has_key?(key.to_sym)
- set_criteria_value(key, value)
- end
+ set_criteria_value(key, value) unless @criteria.has_key?(key.to_sym)
end
private
authorized_project_ids = controller.select_authorized(:user, project_ids)
snapshot_ids = rows.map { |row| row.getSnapshotId() if authorized_project_ids.include?(row.getResourceRootId()) }.compact
@security_exclusions = (snapshot_ids.size<rows.size)
- snapshot_ids
- end
-
- def paginate_snapshot_ids(snapshot_ids)
@pagination.count = snapshot_ids.size
- snapshot_ids[@pagination.offset .. (@pagination.offset+@pagination.limit)]
+ snapshot_ids[@pagination.offset .. (@pagination.offset+@pagination.limit)]
end
def init_data(snapshot_ids)
snapshots.each do |snapshot|
data = Data.new(snapshot)
data_by_snapshot_id[snapshot.id] = data
- @data << data
+ end
+
+ # @data must be in the same order than the snapshot ids
+ snapshot_ids.each do |sid|
+ @data << data_by_snapshot_id[sid]
end
metric_ids = @columns.map { |column| column.metric }.compact.uniq.map { |metric| metric.id }
+<%
+ display_favourites = logged_in?
+ colspan = @filter.columns.size
+ colspan += 1 if display_favourites
+%>
<table class="data">
<thead>
<tr>
+ <% if display_favourites %><th class="thin"></th><% end %>
<% @filter.columns.each do |column| %>
- <% if column.metric %>
- <th class="right"><%= Api::Utils.message("metric.#{column.metric.key}.name", :default => column.metric.short_name) -%></th>
- <% elsif column.key=='name' %>
- <th class="left"><%= Api::Utils.message("filters.col.name") -%></th>
- <% else %>
- <th class="right"><%= Api::Utils.message("filters.col.#{column.key}", :default => column.key) -%></th>
- <% end %>
+ <%= list_column_title(@filter, column, url_params) -%>
<% end %>
</tr>
</thead>
<tbody>
<% @filter.data.each do |data| %>
<tr class="<%= cycle 'even', 'odd' -%>">
+ <% if display_favourites %><td class="thin"><%= link_to_favourite(data.snapshot.resource) -%></td><% end %>
<% @filter.columns.each do |column| %>
<% if column.metric %>
<td class="right">
<% end %>
</tr>
<% end %>
+ <% if @filter.data.empty? %>
+ <tr class="even">
+ <td colspan="<%= colspan -%>"><%= message 'no_data' -%></td>
+ </tr>
+ <% end %>
</tbody>
- <%= render :partial => 'utils/tfoot_pagination', :locals => {:pagination => @filter.pagination, :colspan => @filter.columns.size} %>
+ <%= render :partial => 'utils/tfoot_pagination', :locals => {:pagination => @filter.pagination, :colspan => colspan} %>
</table>
\ No newline at end of file
width: 240px;
}
+ #filter-form select {
+ width: 200px;
+ padding: 1px;
+ }
+
+ #filter-form select option {
+ padding: 1px 10px 1px 4px;
+ }
+
#filter-result {
padding-left: 250px;
}
</style>
<% end %>
-<% url_options = params.reject { |k, v| v.empty? || k=='search' }.merge({:controller => 'measures', :action => 'search'}) %>
+<% url_params = params.reject { |k, v| v.nil? || v=='' || k.starts_with?('_') }.merge({:controller => 'measures', :action => 'search'}) %>
<div id="measure-filter">
<div id="filter-form">
<table>
<tbody>
<tr>
- <td>Base:</td>
- <td><input type="text" name="base"></td>
+ <td>
+ Base:<br>
+ <input type="text" name="base">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Direct children:<br>
+ <%= check_box_tag 'onBaseChildren', 'true', params['onBaseChildren']=='true' -%>
+ </td>
</tr>
<tr>
- <td>Qualifiers:</td>
<td>
- <select name="qualifiers">
- <option value="">Any</option>
- <option value="TRK">Project</option>
- <option value="TRK,BRC">Project</option>
- <option value="DIR,PAC">Directory/Package</option>
- <option value="FIL,CLA">File</option>
- <option value="UTS">Unit Test File</option>
+ Qualifiers:<br>
+ <%= select_tag 'qualifiers[]', options_for_select([['Any', ''], ['Project', 'TRK'], ['Sub-project', 'BRC'], ['Directory/Package', 'DIR']], params['qualifiers']||''), :size => 5, :multiple => true -%>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Language:<br>
+ <select name="languages[]" multiple size="5">
+ <option value="" <%= 'selected' if params['languages[]'].blank? -%>>Any</option>
+ <% Api::Utils.languages.each do |language| %>
+ <option value="<%= language.key.parameterize -%>"><%= h language.name -%></option>
+ <% end %>
</select>
</td>
</tr>
<tr>
- <td>Language:</td>
- <td><input type="text" name="language"></td>
+ <td>
+ Name:<br>
+ <input type="text" name="nameRegexp"></td>
</tr>
<tr>
- <td>Name:</td>
- <td><input type="text" name="nameRegexp"></td>
+ <td>
+ Key:<br>
+ <input type="text" name="keyRegexp"></td>
</tr>
<tr>
- <td>Key:</td>
- <td><input type="text" name="keyRegexp"></td>
+ <td>
+ Favourites only:<br>
+ <%= check_box_tag 'favourites', 'true', params['favourites']=='true' %>
+ </td>
</tr>
<tr>
- <td><input type="submit" name="search" value="Search"></td>
- <td></td>
+ <td>
+ From date:<br>
+ <input type="text" name="fromDate" value="<%= params['fromDate'] -%>">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ To date:<br>
+ <input type="text" name="toDate" value="<%= params['toDate'] -%>">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Before:<br>
+ <input type="text" name="beforeDays" value="<%= params['beforeDays'] -%>" size="4"> days
+ </td>
+ </tr>
+ <tr>
+ <td>After:<br>
+ <input type="text" name="afterDays" value="<%= params['afterDays'] -%>" size="4"> days
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <input type="submit" name="_search" value="Search">
+ <a href="<%= ApplicationController.root_context -%>/measures">Reset</a>
+ </td>
</tr>
</tbody>
</table>
</div>
<% if @filter %>
<div id="filter-result">
+ Display as:
<% MeasureFilter::DISPLAYS.each do |display| %>
- <%= link_to display.key, url_options.merge(:display => display.key) -%>
+ <%= link_to_if display.key!=@filter.display.key, display.key, url_params.merge(:display => display.key) -%>
<% end %>
- <%= render :partial => "measures/display_#{@filter.display.key}.html.erb" -%>
+ <%= render :partial => "measures/display_#{@filter.display.key}", :locals => {:url_params => url_params} -%>
<p>
- <% permalink = url_for(url_options) %>
+ <% permalink = url_for(url_params) %>
<a href="<%= permalink -%>">Permalink</a>: <input type="text" value="<%= permalink -%>" size="100">
</p>
+ <% if @filter.security_exclusions %>
+ <p class="notes"><%= message('results_not_display_due_to_security') -%></p>
+ <% end %>
+
</div>
<% end %>