diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2012-10-09 13:49:01 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2012-10-09 13:49:19 +0200 |
commit | 223d3f26c6391622c0770f3bc65fdbd54b85233c (patch) | |
tree | aa954c15743acd820ecfb7f8500cedc12c6588bd /sonar-server | |
parent | ea1703158c9f4bd3fe57b78222dc2cf10ae45c4c (diff) | |
download | sonarqube-223d3f26c6391622c0770f3bc65fdbd54b85233c.tar.gz sonarqube-223d3f26c6391622c0770f3bc65fdbd54b85233c.zip |
SONAR-3621 use JSON format between rails and java components
This is the first step before the refactoring of the tables FILTERS, FILTER_COLUMNS and CRITERIA
Diffstat (limited to 'sonar-server')
18 files changed, 77 insertions, 1617 deletions
diff --git a/sonar-server/src/dev/h2/conf/logback.xml b/sonar-server/src/dev/h2/conf/logback.xml index 127e47ad786..3ea98589f88 100644 --- a/sonar-server/src/dev/h2/conf/logback.xml +++ b/sonar-server/src/dev/h2/conf/logback.xml @@ -31,6 +31,10 @@ <level value="DEBUG"/> </logger> + <logger name="org.sonar.MEASURE_FILTER"> + <level value="DEBUG"/> + </logger> + <root> <level value="INFO"/> <appender-ref ref="STDOUT"/> diff --git a/sonar-server/src/dev/mysql/conf/logback.xml b/sonar-server/src/dev/mysql/conf/logback.xml index 127e47ad786..3ea98589f88 100644 --- a/sonar-server/src/dev/mysql/conf/logback.xml +++ b/sonar-server/src/dev/mysql/conf/logback.xml @@ -31,6 +31,10 @@ <level value="DEBUG"/> </logger> + <logger name="org.sonar.MEASURE_FILTER"> + <level value="DEBUG"/> + </logger> + <root> <level value="INFO"/> <appender-ref ref="STDOUT"/> diff --git a/sonar-server/src/dev/postgresql/conf/logback.xml b/sonar-server/src/dev/postgresql/conf/logback.xml index 127e47ad786..3ea98589f88 100644 --- a/sonar-server/src/dev/postgresql/conf/logback.xml +++ b/sonar-server/src/dev/postgresql/conf/logback.xml @@ -31,6 +31,10 @@ <level value="DEBUG"/> </logger> + <logger name="org.sonar.MEASURE_FILTER"> + <level value="DEBUG"/> + </logger> + <root> <level value="INFO"/> <appender-ref ref="STDOUT"/> diff --git a/sonar-server/src/main/java/org/sonar/server/filters/DateCriterion.java b/sonar-server/src/main/java/org/sonar/server/filters/DateCriterion.java deleted file mode 100644 index b1c290386be..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/filters/DateCriterion.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.server.filters; - -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; -import org.apache.commons.lang.time.DateUtils; - -import java.util.Calendar; -import java.util.Date; - -public class DateCriterion { - - private String operator; - private Date date; - - public DateCriterion(String operator, Date date) { - this.operator = operator; - this.date = date; - } - - public DateCriterion() { - } - - public String getOperator() { - return operator; - } - - public DateCriterion setOperator(String operator) { - this.operator = operator; - return this; - } - - public Date getDate() { - return date; - } - - public DateCriterion setDate(Date date) { - this.date = date; - return this; - } - - public DateCriterion setDate(int daysAgo) { - this.date = DateUtils.addDays(new Date(), -daysAgo); - this.date = DateUtils.truncate(this.date, Calendar.DATE); - return this; - } - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) - .append("operator", operator) - .append("date", date) - .toString(); - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/filters/Filter.java b/sonar-server/src/main/java/org/sonar/server/filters/Filter.java deleted file mode 100644 index 351477d93ed..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/filters/Filter.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * 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.server.filters; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; -import org.sonar.api.resources.Qualifiers; - -import java.util.List; -import java.util.Set; - -public class Filter { - - // path - private Integer rootSnapshotId; - private Integer baseSnapshotId; - private String baseSnapshotPath; - - // filters on resources - private Set<String> scopes; - private Set<String> qualifiers; - private Set<String> languages; - private Set<Integer> favouriteIds; - private DateCriterion dateCriterion; - private String keyRegexp; - private String nameRegexp; - private boolean onDirectChildren = false; - - // filters on measures - private List<MeasureCriterion> measureCriteria = Lists.newLinkedList(); - private int periodIndex = 0; - - // sorting - private Integer sortedMetricId; - private Boolean sortedByMeasureVariation = Boolean.FALSE; - private boolean sortedByLanguage; - private boolean sortedByName; - private boolean sortedByKey; - private boolean sortedByDate; - private boolean sortedByVersion; - private boolean isNumericMetric = true; - private boolean ascendingSort = true; - - public Filter setPath(Integer rootSnapshotId, Integer snapshotId, String snapshotPath) { - this.baseSnapshotId = snapshotId; - if (rootSnapshotId == null) { - this.rootSnapshotId = snapshotId; - } else { - this.rootSnapshotId = rootSnapshotId; - } - this.baseSnapshotPath = StringUtils.defaultString(snapshotPath, ""); //With Oracle the path can be null (see SONAR-2582) - return this; - } - - public Integer getRootSnapshotId() { - return rootSnapshotId; - } - - public boolean hasBaseSnapshot() { - return baseSnapshotId != null; - } - - public Integer getBaseSnapshotId() { - return baseSnapshotId; - } - - public String getBaseSnapshotPath() { - return baseSnapshotPath; - } - - public Set<String> getScopes() { - return scopes; - } - - public boolean hasScopes() { - return scopes != null && !scopes.isEmpty(); - } - - public Filter setScopes(Set<String> scopes) { - this.scopes = scopes; - return this; - } - - public Filter setScopes(String... scopes) { - this.scopes = Sets.newHashSet(scopes); - return this; - } - - public Set<String> getQualifiers() { - return qualifiers; - } - - public boolean hasQualifiers() { - return qualifiers != null && !qualifiers.isEmpty(); - } - - public Filter setQualifiers(Set<String> qualifiers) { - this.qualifiers = qualifiers; - return this; - } - - public Filter setQualifiers(String... qualifiers) { - this.qualifiers = Sets.newHashSet(qualifiers); - return this; - } - - public Set<String> getLanguages() { - return languages; - } - - public boolean hasLanguages() { - return languages != null && !languages.isEmpty(); - } - - public Filter setLanguages(Set<String> languages) { - this.languages = languages; - return this; - } - - public Filter setLanguages(String... languages) { - this.languages = Sets.newHashSet(languages); - return this; - } - - public Set<Integer> getFavouriteIds() { - return favouriteIds; - } - - public boolean hasFavouriteIds() { - return favouriteIds != null && !favouriteIds.isEmpty(); - } - - public Filter setFavouriteIds(Set<Integer> favouriteIds) { - this.favouriteIds = favouriteIds; - return this; - } - - public Filter setFavouriteIds(Integer... favouriteIds) { - this.favouriteIds = Sets.newHashSet(favouriteIds); - return this; - } - - public Integer getSortedMetricId() { - return sortedMetricId; - } - - public boolean isNumericMetric() { - return isNumericMetric; - } - - public boolean isTextSort() { - return !isNumericMetric || sortedByLanguage || sortedByName || sortedByVersion || sortedByKey; - } - - public Filter setSortedMetricId(Integer id, boolean isNumericValue, Boolean isVariation) { - unsetSorts(); - this.sortedMetricId = id; - this.isNumericMetric = isNumericValue; - this.sortedByMeasureVariation = isVariation; - return this; - } - - public boolean isSortedByLanguage() { - return sortedByLanguage; - } - - public Filter setSortedByLanguage() { - unsetSorts(); - this.sortedByLanguage = true; - return this; - } - - public boolean isSortedByName() { - return sortedByName; - } - - public boolean isSortedByKey() { - return sortedByKey; - } - - public boolean isSortedByVersion() { - return sortedByVersion; - } - - public Filter setSortedByVersion() { - unsetSorts(); - this.sortedByVersion = true; - return this; - } - - public boolean isSorted() { - return isSortedByLanguage() || isSortedByName() || isSortedByKey() || isSortedByDate() || isSortedByVersion() || getSortedMetricId() != null; - } - - public boolean isSortedByDate() { - return sortedByDate; - } - - public Filter setSortedByDate() { - unsetSorts(); - sortedByDate = true; - return this; - } - - public Filter setSortedByName() { - unsetSorts(); - this.sortedByName = true; - return this; - } - - public Filter setSortedByKey() { - unsetSorts(); - this.sortedByKey = true; - return this; - } - - private void unsetSorts() { - this.sortedByDate = false; - this.sortedByLanguage = false; - this.sortedByName = false; - this.sortedByKey = false; - this.sortedMetricId = null; - this.sortedByVersion = false; - this.isNumericMetric = true; - } - - public List<MeasureCriterion> getMeasureCriteria() { - return measureCriteria; - } - - public Filter setMeasureCriteria(List<MeasureCriterion> l) { - this.measureCriteria = l; - return this; - } - - public Filter addMeasureCriterion(MeasureCriterion c) { - this.measureCriteria.add(c); - return this; - } - - public Filter createMeasureCriterionOnValue(Integer metricId, String operator, Double value, Boolean variation) { - this.measureCriteria.add(new MeasureCriterion(metricId, operator, value, variation)); - return this; - } - - public boolean hasMeasureCriteria() { - return !measureCriteria.isEmpty(); - } - - protected boolean hasMeasureCriteriaOnMetric(Integer metricId) { - if (metricId != null) { - for (MeasureCriterion criterion : measureCriteria) { - if (metricId.equals(criterion.getMetricId())) { - return true; - } - } - } - return false; - } - - public boolean mustJoinMeasuresTable() { - return sortedMetricId != null || hasMeasureCriteria(); - } - - public boolean isAscendingSort() { - return ascendingSort; - } - - public Filter setAscendingSort(boolean b) { - this.ascendingSort = b; - return this; - } - - public DateCriterion getDateCriterion() { - return dateCriterion; - } - - public Filter setDateCriterion(DateCriterion dc) { - this.dateCriterion = dc; - return this; - } - - public Filter setDateCriterion(String operator, Integer daysAgo) { - this.dateCriterion = new DateCriterion().setOperator(operator).setDate(daysAgo); - return this; - } - - public String getKeyRegexp() { - return keyRegexp; - } - - public Filter setKeyRegexp(String s) { - this.keyRegexp = s; - return this; - } - - public String getNameRegexp() { - return nameRegexp; - } - - public Filter setNameRegexp(String s) { - this.nameRegexp = s; - return this; - } - - public int getPeriodIndex() { - return periodIndex; - } - - public void setPeriodIndex(int i) { - this.periodIndex = i; - } - - public boolean isOnPeriod() { - return periodIndex > 0; - } - - public boolean isOnDirectChildren() { - return onDirectChildren; - } - - public void setOnDirectChildren(boolean b) { - this.onDirectChildren = b; - } - - static String getVariationColumn(int periodIndex) { - switch (periodIndex) { - case 1: - return "variation_value_1"; - case 2: - return "variation_value_2"; - case 3: - return "variation_value_3"; - case 4: - return "variation_value_4"; - case 5: - return "variation_value_5"; - default: - return null; - } - } - - String getColumnToSort() { - String col = "text_value"; - if (isNumericMetric()) { - col = (sortedByMeasureVariation == Boolean.TRUE ? getVariationColumn(periodIndex) : "value"); - } - return col; - } - - public boolean mustReturnEmptyResult() { - boolean hasCriterionOnVariation = false; - for (MeasureCriterion criterion : measureCriteria) { - if (criterion.isVariation() == Boolean.TRUE) { - hasCriterionOnVariation = true; - } - } - return (hasCriterionOnVariation && !isOnPeriod()); - } - - @Override - public String toString() { - return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE); - } - - public static Filter createForAllQualifiers() { - return new Filter().setQualifiers( - Qualifiers.VIEW, Qualifiers.SUBVIEW, - Qualifiers.PROJECT, Qualifiers.MODULE, Qualifiers.DIRECTORY, Qualifiers.PACKAGE, - Qualifiers.FILE, Qualifiers.CLASS, Qualifiers.UNIT_TEST_FILE, Qualifiers.LIBRARY, Qualifiers.PARAGRAPH); - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java b/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java deleted file mode 100644 index c3d0f26e2fb..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/filters/FilterExecutor.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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.server.filters; - -import com.google.common.annotations.VisibleForTesting; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.ServerComponent; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.utils.SonarException; -import org.sonar.api.utils.TimeProfiler; -import org.sonar.core.persistence.Database; -import org.sonar.core.persistence.dialect.Dialect; -import org.sonar.core.persistence.dialect.MsSql; - -import javax.persistence.Query; - -import java.util.Collections; - -public class FilterExecutor implements ServerComponent { - private static final Logger LOG = LoggerFactory.getLogger(FilterExecutor.class); - private static final int SQL_INITIAL_SIZE = 1000; - private DatabaseSession session; - private Dialect dialect; - - public FilterExecutor(DatabaseSession session, Database database) { - this(session, database.getDialect()); - } - - @VisibleForTesting - FilterExecutor(DatabaseSession session, Dialect dialect) { - this.session = session; - this.dialect = dialect; - } - - public FilterResult execute(Filter filter) { - if (filter.mustReturnEmptyResult()) { - return new FilterResult(filter, Collections.<Object[]> emptyList()); - } - - String sql = null; - try { - TimeProfiler profiler = new TimeProfiler(FilterExecutor.class).setLevelToDebug().start("Build/execute SQL query"); - sql = toSql(filter); - LOG.debug("SQL: " + sql); - Query query = session.getEntityManager().createNativeQuery(sql); - setHqlParameters(filter, query); - FilterResult result = new FilterResult(filter, query.getResultList()); - profiler.stop(); - - profiler.start("Process rows"); - result.removeUnvalidRows(); - profiler.stop(); - - profiler.start("Sort rows"); - result.sort(); - profiler.stop(); - return result; - - } catch (Exception e) { - throw new SonarException("Fail to execute filter: " + filter.toString() + ", sql=" + sql, e); - } - } - - @VisibleForTesting - String toSql(Filter filter) { - StringBuilder sql = new StringBuilder(SQL_INITIAL_SIZE); - addSelectColumns(filter, sql); - addFromClause(filter, sql); - addWhereClause(filter, sql); - return sql.toString(); - } - - private void addSelectColumns(Filter filter, StringBuilder sql) { - sql.append("SELECT s.id, MAX(s.project_id) as pid, MAX(s.root_project_id) as rpid"); - if (filter.isSortedByLanguage()) { - sql.append(", MAX(p.language) as lang "); - - } else if (filter.isSortedByName()) { - sql.append(", MAX(p.long_name) as name "); - - } else if (filter.isSortedByKey()) { - sql.append(", MAX(p.kee) as kee "); - - } else if (filter.isSortedByDate()) { - sql.append(", MAX(s.created_at) as createdat "); - - } else if (filter.isSortedByVersion()) { - sql.append(", MAX(s.version) as version "); - } - if (filter.getSortedMetricId() != null) { - sql.append(", MAX(CASE WHEN pm.metric_id="); - sql.append(filter.getSortedMetricId()); - sql.append(" THEN "); - sql.append(filter.getColumnToSort()); - sql.append(" ELSE NULL END) AS sortvalue"); - sql.append(" "); - } - for (int index = 0; index < filter.getMeasureCriteria().size(); index++) { - MeasureCriterion criterion = filter.getMeasureCriteria().get(index); - String column = (criterion.isVariation() ? Filter.getVariationColumn(filter.getPeriodIndex()) : "value"); - sql.append(", MAX(CASE WHEN pm.metric_id="); - sql.append(criterion.getMetricId()); - sql.append(" AND pm."); - sql.append(column); - sql.append(criterion.getOperator()); - sql.append(criterion.getValue()); - sql.append(" THEN "); - sql.append(column); - sql.append(" ELSE NULL END) AS crit_"); - sql.append(index); - sql.append(" "); - } - } - - private void addFromClause(Filter filter, StringBuilder sql) { - sql.append(" FROM snapshots s "); - if (filter.mustJoinMeasuresTable()) { - sql.append(" INNER JOIN project_measures pm "); - if (MsSql.ID.equals(dialect.getId())) { - // SONAR-3422 - sql.append(" WITH (INDEX(measures_sid_metric)) "); - } - sql.append(" ON s.id=pm.snapshot_id "); - } - sql.append(" INNER JOIN projects p ON s.project_id=p.id "); - } - - private void addWhereClause(Filter filter, StringBuilder sql) { - sql.append(" WHERE "); - if (filter.mustJoinMeasuresTable()) { - if (filter.hasMeasureCriteria()) { - sql.append(" ( "); - int index = 0; - while (index < filter.getMeasureCriteria().size()) { - if (index > 0) { - sql.append(" OR "); - } - MeasureCriterion criterion = filter.getMeasureCriteria().get(index); - String column = (criterion.isVariation() ? Filter.getVariationColumn(filter.getPeriodIndex()) : "value"); - sql.append("(pm.metric_id=").append(criterion.getMetricId()).append(" and pm.").append(column) - .append(criterion.getOperator()).append(criterion.getValue()).append(")"); - index++; - } - - if (filter.getSortedMetricId() != null && !filter.hasMeasureCriteriaOnMetric(filter.getSortedMetricId())) { - sql.append(" OR (pm.metric_id=").append(filter.getSortedMetricId()).append(") "); - } - - sql.append(" ) AND "); - } - sql.append(" pm.rule_id IS NULL AND pm.rule_priority IS NULL"); - sql.append(" AND pm.characteristic_id IS NULL"); - sql.append(" AND pm.person_id IS NULL"); - sql.append(" AND "); - } - sql.append(" s.status=:status AND s.islast=:islast "); - if (filter.getScopes() != null) { - sql.append(filter.getScopes().isEmpty() ? " AND s.scope IS NULL " : " AND s.scope IN (:scopes) "); - } - if (filter.hasQualifiers()) { - sql.append(" AND s.qualifier IN (:qualifiers) "); - } else if (!filter.isOnDirectChildren()) { - // no criteria -> we should not display all rows but no rows - sql.append(" AND s.qualifier IS NULL "); - } - if (filter.hasLanguages()) { - sql.append(" AND p.language IN (:languages) "); - } - if (filter.getFavouriteIds() != null) { - sql.append(filter.getFavouriteIds().isEmpty() ? " AND s.project_id IS NULL " : " AND s.project_id IN (:favourites) "); - } - if (filter.hasBaseSnapshot()) { - if (filter.isOnDirectChildren()) { - sql.append(" AND s.parent_snapshot_id=:parent_sid "); - } else { - sql.append(" AND s.root_snapshot_id=:root_sid AND s.path LIKE :path "); - } - } - if (filter.getDateCriterion() != null) { - sql.append(" AND s.created_at"); - sql.append(filter.getDateCriterion().getOperator()); - sql.append(" :date "); - } - if (StringUtils.isNotBlank(filter.getKeyRegexp())) { - sql.append(" AND UPPER(p.kee) LIKE :kee"); - } - if (StringUtils.isNotBlank(filter.getNameRegexp())) { - sql.append(" AND UPPER(p.long_name) LIKE :name"); - } - if (!filter.hasBaseSnapshot()) { - sql.append(" AND p.copy_resource_id IS NULL "); - } - sql.append(" GROUP BY s.id"); - } - - private void setHqlParameters(Filter filter, Query query) { - query.setParameter("status", Snapshot.STATUS_PROCESSED); - query.setParameter("islast", true); - if (filter.hasScopes()) { - query.setParameter("scopes", filter.getScopes()); - } - if (filter.hasQualifiers()) { - query.setParameter("qualifiers", filter.getQualifiers()); - } - if (filter.hasLanguages()) { - query.setParameter("languages", filter.getLanguages()); - } - if (filter.hasFavouriteIds()) { - query.setParameter("favourites", filter.getFavouriteIds()); - } - if (filter.getDateCriterion() != null) { - query.setParameter("date", filter.getDateCriterion().getDate()); - } - if (filter.hasBaseSnapshot()) { - if (filter.isOnDirectChildren()) { - query.setParameter("parent_sid", filter.getBaseSnapshotId()); - } else { - query.setParameter("root_sid", filter.getRootSnapshotId()); - query.setParameter("path", new StringBuilder().append( - filter.getBaseSnapshotPath()).append(filter.getBaseSnapshotId()).append(".%").toString()); - } - } - if (StringUtils.isNotBlank(filter.getKeyRegexp())) { - query.setParameter("kee", StringUtils.upperCase(StringUtils.replaceChars(filter.getKeyRegexp(), '*', '%'))); - } - if (StringUtils.isNotBlank(filter.getNameRegexp())) { - query.setParameter("name", StringUtils.upperCase(StringUtils.replaceChars(filter.getNameRegexp(), '*', '%'))); - } - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/filters/FilterResult.java b/sonar-server/src/main/java/org/sonar/server/filters/FilterResult.java deleted file mode 100644 index 87987537c0f..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/filters/FilterResult.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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.server.filters; - -import com.google.common.collect.Ordering; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; - -public class FilterResult { - private List<Object[]> rows; - private Filter filter; - public static final int SORTED_COLUMN_INDEX = 3; - - public FilterResult(Filter filter, List<Object[]> rows) { - this.rows = new ArrayList<Object[]>(rows); - this.filter = filter; - } - - /** - * @return a list of arrays - */ - public List<Object[]> getRows() { - return rows; - } - - public int size() { - return rows.size(); - } - - public Integer getSnapshotId(Object[] row) { - return (Integer) row[getSnapshotIdIndex()]; - } - - public Integer getProjectId(Object[] row) { - return (Integer) row[getProjectIdIndex()]; - } - - public Integer getRootProjectId(Object[] row) { - return (Integer) row[getRootProjectIdIndex()]; - } - - public int getSnapshotIdIndex() { - return 0; - } - - public int getProjectIdIndex() { - return 1; - } - - public int getRootProjectIdIndex() { - return 2; - } - - public void sort() { - if (filter.isSorted()) { - Comparator<Object[]> comparator = (filter.isTextSort() ? new StringIgnoreCaseComparator(SORTED_COLUMN_INDEX) : new NumericComparator(SORTED_COLUMN_INDEX)); - if (!filter.isAscendingSort()) { - comparator = Ordering.from(comparator).reverse(); - } - Collections.sort(rows, comparator); - } - } - - public void removeUnvalidRows() { - int numberOfCriteria = filter.getMeasureCriteria().size(); - if (numberOfCriteria > 0) { - int fromColumnIndex = (filter.isSorted() ? SORTED_COLUMN_INDEX + 1 : SORTED_COLUMN_INDEX); - for (Iterator<Object[]> it = rows.iterator(); it.hasNext(); ) { - Object[] row = it.next(); - boolean remove = false; - for (int index = 0; index < numberOfCriteria; index++) { - if (row[fromColumnIndex + index] == null) { - remove = true; - } - } - if (remove) { - it.remove(); - } - } - } - } - - static final class NumericComparator implements Comparator<Object[]>, Serializable { - private static final long serialVersionUID = 4627704879575964978L; - private int index; - - NumericComparator(int index) { - this.index = index; - } - - public int compare(Object[] a1, Object[] a2) { - Comparable c1 = (Comparable) a1[index]; - Comparable o2 = (Comparable) a2[index]; - - return (c1 == null ? -1 : (o2 == null ? 1 : c1.compareTo(o2))); - } - } - - static final class StringIgnoreCaseComparator implements Comparator<Object[]>, Serializable { - private static final long serialVersionUID = 963926659201833101L; - private int index; - - StringIgnoreCaseComparator(int index) { - this.index = index; - } - - public int compare(Object[] o1, Object[] o2) { - String s1 = (String) o1[index]; - if (s1 == null) { - return -1; - } - String s2 = (String) o2[index]; - if (s2 == null) { - return 1; - } - return s1.compareToIgnoreCase(s2); - } - } -} - diff --git a/sonar-server/src/main/java/org/sonar/server/filters/MeasureCriterion.java b/sonar-server/src/main/java/org/sonar/server/filters/MeasureCriterion.java deleted file mode 100644 index 2413df514a4..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/filters/MeasureCriterion.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.server.filters; - -import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; - -public class MeasureCriterion { - - private Integer metricId; - private String operator; - private Double value; - private Boolean variation; - - public MeasureCriterion(Integer metricId, String operator, Double value, Boolean variation) { - this.metricId = metricId; - this.operator = operator; - this.value = value; - this.variation = variation; - } - - public Integer getMetricId() { - return metricId; - } - - public void setMetricId(Integer metricId) { - this.metricId = metricId; - } - - public String getOperator() { - return operator; - } - - public void setOperator(String operator) { - this.operator = operator; - } - - public Double getValue() { - return value; - } - - public void setValue(Double value) { - this.value = value; - } - - public boolean isVariation() { - return variation==Boolean.TRUE; - } - - public MeasureCriterion setVariation(Boolean b) { - this.variation = b; - return this; - } - - @Override - public String toString() { - return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString(); - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 56ae61b787f..83ae16377ae 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -42,13 +42,12 @@ import org.sonar.core.config.Logback; import org.sonar.core.i18n.GwtI18n; import org.sonar.core.i18n.I18nManager; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.measure.MeasureFilterDecoder; +import org.sonar.core.measure.MeasureFilterEngine; +import org.sonar.core.measure.MeasureFilterExecutor; import org.sonar.core.metric.DefaultMetricFinder; import org.sonar.core.notification.DefaultNotificationManager; -import org.sonar.core.persistence.DaoUtils; -import org.sonar.core.persistence.DatabaseMigrator; -import org.sonar.core.persistence.DatabaseVersion; -import org.sonar.core.persistence.DefaultDatabase; -import org.sonar.core.persistence.MyBatis; +import org.sonar.core.persistence.*; import org.sonar.core.qualitymodel.DefaultModelFinder; import org.sonar.core.rule.DefaultRuleFinder; import org.sonar.core.user.DefaultUserFinder; @@ -65,25 +64,14 @@ import org.sonar.server.charts.ChartFactory; import org.sonar.server.configuration.Backup; import org.sonar.server.configuration.ProfilesManager; import org.sonar.server.database.EmbeddedDatabaseFactory; -import org.sonar.server.filters.FilterExecutor; import org.sonar.server.notifications.NotificationService; import org.sonar.server.notifications.reviews.ReviewsNotificationManager; -import org.sonar.server.plugins.ApplicationDeployer; -import org.sonar.server.plugins.DefaultServerPluginRepository; -import org.sonar.server.plugins.PluginDeployer; -import org.sonar.server.plugins.PluginDownloader; -import org.sonar.server.plugins.ServerExtensionInstaller; -import org.sonar.server.plugins.UpdateCenterClient; -import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.server.plugins.*; import org.sonar.server.qualitymodel.DefaultModelManager; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.server.startup.*; -import org.sonar.server.ui.CodeColorizers; -import org.sonar.server.ui.JRubyI18n; -import org.sonar.server.ui.PageDecorations; -import org.sonar.server.ui.SecurityRealmFactory; -import org.sonar.server.ui.Views; +import org.sonar.server.ui.*; import javax.servlet.ServletContext; @@ -203,7 +191,6 @@ public final class Platform { servicesContainer.addSingleton(UpdateCenterMatrixFactory.class); servicesContainer.addSingleton(PluginDownloader.class); servicesContainer.addSingleton(ServerIdGenerator.class); - servicesContainer.addComponent(FilterExecutor.class, false); servicesContainer.addSingleton(DefaultModelFinder.class); // depends on plugins servicesContainer.addSingleton(DefaultModelManager.class); servicesContainer.addSingleton(Plugins.class); @@ -233,6 +220,9 @@ public final class Platform { servicesContainer.addSingleton(NewUserNotifier.class); servicesContainer.addSingleton(SettingsChangeNotifier.class); servicesContainer.addSingleton(PageDecorations.class); + servicesContainer.addSingleton(MeasureFilterDecoder.class); + servicesContainer.addSingleton(MeasureFilterExecutor.class); + servicesContainer.addSingleton(MeasureFilterEngine.class); // Notifications servicesContainer.addSingleton(EmailSettings.class); diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index b588f82a924..9f52e40f9b1 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -38,16 +38,14 @@ import org.sonar.api.resources.ResourceTypes; import org.sonar.api.rules.RulePriority; import org.sonar.api.rules.RuleRepository; import org.sonar.api.utils.ValidationMessages; -import org.sonar.api.web.Footer; -import org.sonar.api.web.NavigationSection; -import org.sonar.api.web.Page; -import org.sonar.api.web.RubyRailsWebservice; -import org.sonar.api.web.Widget; +import org.sonar.api.web.*; import org.sonar.api.workflow.Review; import org.sonar.api.workflow.internal.DefaultReview; import org.sonar.api.workflow.internal.DefaultWorkflowContext; import org.sonar.api.workflow.screen.Screen; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.measure.MeasureFilterEngine; +import org.sonar.core.measure.MeasureFilterRow; import org.sonar.core.persistence.Database; import org.sonar.core.persistence.DatabaseMigrator; import org.sonar.core.purge.PurgeDao; @@ -57,26 +55,14 @@ import org.sonar.core.workflow.WorkflowEngine; import org.sonar.markdown.Markdown; import org.sonar.server.configuration.Backup; import org.sonar.server.configuration.ProfilesManager; -import org.sonar.server.filters.Filter; -import org.sonar.server.filters.FilterExecutor; -import org.sonar.server.filters.FilterResult; import org.sonar.server.notifications.reviews.ReviewsNotificationManager; -import org.sonar.server.platform.NewUserNotifier; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.ServerIdGenerator; -import org.sonar.server.platform.ServerSettings; -import org.sonar.server.platform.SettingsChangeNotifier; -import org.sonar.server.plugins.DefaultServerPluginRepository; -import org.sonar.server.plugins.PluginDeployer; -import org.sonar.server.plugins.PluginDownloader; -import org.sonar.server.plugins.UpdateCenterMatrix; -import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.server.platform.*; +import org.sonar.server.plugins.*; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.updatecenter.common.Version; import javax.annotation.Nullable; - import java.net.InetAddress; import java.sql.Connection; import java.util.Collection; @@ -97,8 +83,8 @@ public final class JRubyFacade { return getContainer().getComponentByType(componentType); } - public FilterResult executeFilter(Filter filter) { - return get(FilterExecutor.class).execute(filter); + public List<MeasureFilterRow> executeMeasureFilter(String json, @Nullable Long userId) throws Exception { + return get(MeasureFilterEngine.class).execute(json, userId); } public Collection<ResourceType> getResourceTypesForFilter() { @@ -313,7 +299,7 @@ public final class JRubyFacade { public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) { getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId], - RulePriority.values()[newSeverityId], userName); + RulePriority.values()[newSeverityId], userName); } public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) { @@ -509,10 +495,10 @@ public final class JRubyFacade { // notifier is null when creating the administrator in the migration script 011. if (notifier != null) { notifier.onNewUser(NewUserHandler.Context.builder() - .setLogin(fields.get("login")) - .setName(fields.get("name")) - .setEmail(fields.get("email")) - .build()); + .setLogin(fields.get("login")) + .setName(fields.get("name")) + .setEmail(fields.get("email")) + .build()); } } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/filter.rb index 07c04795132..471cc457536 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/filter.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/filter.rb @@ -168,7 +168,7 @@ class Filter < ActiveRecord::Base def on_direct_children? if resource_id c = criterion('direct-children') - c && c.text_value=='true' + c ? c.text_value=='true' : false else false end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/filter_context.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/filter_context.rb index 060e743aae4..f3346ab7634 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/filter_context.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/filter_context.rb @@ -135,25 +135,15 @@ private - def extract_snapshot_ids(sql_rows) + def extract_snapshot_ids(filter_rows) sids=[] - project_ids=sql_rows.map{|r| r[2] ? to_integer(r[2]) : to_integer(r[1])}.compact.uniq + project_ids=filter_rows.map{|row| row.getResourceRootId()}.compact.uniq authorized_pids=select_authorized(:user, project_ids) - sql_rows.each do |row| - pid=(row[2] ? to_integer(row[2]) : to_integer(row[1])) - if authorized_pids.include?(pid) - sids<<to_integer(row[0]) + filter_rows.each do |row| + if authorized_pids.include?(row.getResourceRootId()) + sids<<row.getSnapshotId() end end sids end - - def to_integer(obj) - if obj.is_a?(Fixnum) - obj - else - # java.math.BigDecimal - obj.intValue() - end - end end
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/filters.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/filters.rb index c687797f14d..67198337ad8 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/filters.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/filters.rb @@ -21,82 +21,71 @@ class Filters def self.execute(filter, authenticated_system, options={}) filter_context = FilterContext.new(filter, options) - java_filter=Java::OrgSonarServerFilters::Filter.new + + filter_json={} #----- FILTER ON RESOURCES if filter.resource_id - snapshot=Snapshot.find(:first, :conditions => {:project_id => filter.resource_id, :islast => true}) - if snapshot - java_filter.setPath(snapshot.root_snapshot_id, snapshot.id, snapshot.path) - else - java_filter.setPath(-1, -1, '') - end + filter_json[:base]=filter.resource.key end if filter.favourites - java_filter.setFavouriteIds((authenticated_system.current_user.favourite_ids||[]).to_java(:Integer)) + filter_json[:favourites]=true end date_criterion=filter.criterion('date') if date_criterion - java_filter.setDateCriterion(date_criterion.operator, date_criterion.value.to_i) + if date_criterion.operator=='<' + filter_json[:beforeDays]=date_criterion.value.to_i + else + filter_json[:afterDays]=date_criterion.value.to_i + end end key_criterion=filter.criterion('key') if key_criterion - java_filter.setKeyRegexp(key_criterion.text_value) + #java_filter.setKeyRegexp(key_criterion.text_value) end name_criterion=filter.criterion('name') if name_criterion - java_filter.setNameRegexp(name_criterion.text_value) + filter_json[:name]=name_criterion.text_value end qualifier_criterion=filter.criterion('qualifier') if qualifier_criterion - java_filter.setQualifiers(qualifier_criterion.text_values.to_java(:String)) - else - java_filter.setQualifiers([].to_java(:String)) + filter_json[:qualifiers]=qualifier_criterion.text_values end - java_filter.setOnDirectChildren(filter.on_direct_children?) + filter_json[:onBaseChildren]=filter.on_direct_children? language_criterion=filter.criterion('language') if language_criterion - java_filter.setLanguages(language_criterion.text_values.to_java :String) + filter_json[:languages]=language_criterion.text_values end #----- FILTER ON MEASURES - filter.measure_criteria.each do |c| - java_filter.createMeasureCriterionOnValue(c.metric.id, c.operator, c.value, c.variation) + filter_json[:conditions]=filter.measure_criteria.map do |c| + hash = {:metric => c.metric.key, :op => c.operator, :val => c.value} + if c.variation + hash[:period] = filter_context.period_index || -1 + end + hash end #----- SORTED COLUMN - if filter_context.sorted_column_id filter.sorted_column=filter_context.sorted_column_id end if filter.sorted_column - if filter.sorted_column.on_name? - java_filter.setSortedByName() - - elsif filter.sorted_column.on_date? - java_filter.setSortedByDate() - - elsif filter.sorted_column.on_version? - java_filter.setSortedByVersion() - - elsif filter.sorted_column.on_language? - java_filter.setSortedByLanguage() - - elsif filter.sorted_column.on_key? - java_filter.setSortedByKey() - - elsif filter.sorted_column.on_metric? && filter.sorted_column.metric - metric=filter.sorted_column.metric - java_filter.setSortedMetricId(metric.id, metric.numeric?, filter.sorted_column.variation) + filter_json[:sortField]=filter.sorted_column.family.upcase + if filter.sorted_column.on_metric? && filter.sorted_column.metric + filter_json[:sortMetric]=filter.sorted_column.metric.key + if filter.sorted_column.variation + filter_json[:sortPeriod]=filter_context.period_index || -1 + end end end @@ -104,51 +93,39 @@ class Filters #----- SORTING DIRECTION if filter.sorted_column if filter_context.ascending_sort.nil? - java_filter.setAscendingSort(filter.sorted_column.ascending?) + filter_json[:sortAsc]=filter.sorted_column.ascending? else filter.sorted_column.ascending=filter_context.ascending_sort - java_filter.setAscendingSort(filter.sorted_column.ascending?) + filter_json[:sortAsc]=filter.sorted_column.ascending? end if filter_context.ascending_sort filter.sorted_column.ascending=filter_context.ascending_sort end - java_filter.setAscendingSort(filter.sorted_column.ascending?) + filter_json[:sortAsc]=filter.sorted_column.ascending? end - #----- VARIATION - java_filter.setPeriodIndex(filter_context.period_index) - #----- EXECUTION - java_result=Java::OrgSonarServerUi::JRubyFacade.getInstance().execute_filter(java_filter) - snapshot_ids=extract_snapshot_ids(java_result.getRows(), authenticated_system) + user=authenticated_system.current_user + rows=Api::Utils.java_facade.executeMeasureFilter(filter_json.to_json, user ? user.id : nil) + snapshot_ids=extract_snapshot_ids(rows, authenticated_system) - has_security_exclusions=(snapshot_ids.size < java_result.size()) + has_security_exclusions=(snapshot_ids.size < rows.size) filter_context.process_results(snapshot_ids, has_security_exclusions) filter_context end private - def self.extract_snapshot_ids(sql_rows, authenticated_system) + def self.extract_snapshot_ids(rows, authenticated_system) sids=[] - project_ids=sql_rows.map { |r| r[2] ? to_integer(r[2]) : to_integer(r[1]) }.compact.uniq + project_ids=rows.map { |row| row.getResourceRootId() }.compact.uniq authorized_pids=authenticated_system.select_authorized(:user, project_ids) - sql_rows.each do |row| - pid=(row[2] ? to_integer(row[2]) : to_integer(row[1])) - if authorized_pids.include?(pid) - sids<<to_integer(row[0]) + rows.each do |row| + if authorized_pids.include?(row.getResourceRootId()) + sids<<row.getSnapshotId() end end sids end - - def self.to_integer(obj) - if obj.is_a?(Fixnum) - obj - else - # java.math.BigDecimal - obj.intValue() - end - end end
\ No newline at end of file diff --git a/sonar-server/src/test/java/org/sonar/server/filters/DateCriterionTest.java b/sonar-server/src/test/java/org/sonar/server/filters/DateCriterionTest.java deleted file mode 100644 index 7f251513619..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/filters/DateCriterionTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.server.filters; - -import org.apache.commons.lang.time.DateUtils; -import org.junit.Test; - -import java.util.Date; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -public class DateCriterionTest { - @Test - public void ignoreTime() { - DateCriterion criterion = new DateCriterion().setDate(3); - Date date = criterion.getDate(); - assertThat(date.getHours(), is(0)); - assertThat(date.getMinutes(), is(0)); - } - - @Test - public void testDaysAgo() { - DateCriterion criterion = new DateCriterion().setDate(3); - Date date = criterion.getDate(); - assertThat(date.getMinutes(), is(0)); - assertThat(date.getHours(), is(0)); - assertThat(DateUtils.isSameDay(date, DateUtils.addDays(new Date(), -3)), is(true)); - } -} diff --git a/sonar-server/src/test/java/org/sonar/server/filters/FilterExecutorTest.java b/sonar-server/src/test/java/org/sonar/server/filters/FilterExecutorTest.java deleted file mode 100644 index 8ed6c98b2bc..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/filters/FilterExecutorTest.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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.server.filters; - -import com.google.common.collect.Sets; -import org.junit.Test; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Resource; -import org.sonar.core.persistence.dialect.H2; -import org.sonar.core.persistence.dialect.MsSql; -import org.sonar.jpa.test.AbstractDbUnitTestCase; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; - -import static org.fest.assertions.Assertions.assertThat; -import static org.fest.assertions.Fail.fail; - -public class FilterExecutorTest extends AbstractDbUnitTestCase { - - @Test - public void mustDefineAtLeastOneQualifier() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(new Filter()); - assertThat(result.size()).isEqualTo(0);// no qualifiers - } - - @Test - public void filterOnScopes() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setScopes(Sets.newHashSet(Resource.SCOPE_SPACE))); - assertSnapshotIds(result, 4); - } - - @Test - public void filterOnQualifiers() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(new Filter().setQualifiers(Sets.newHashSet(Resource.QUALIFIER_PROJECT, Resource.QUALIFIER_MODULE))); - assertSnapshotIds(result, 2, 3); - } - - @Test - public void filterOnLanguages() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setLanguages(Sets.newHashSet("java"))); - assertSnapshotIds(result, 2, 4); - } - - @Test - public void filterOnDate() throws ParseException { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse("2008-12-26 00:00"); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setDateCriterion(new DateCriterion(">", date))); - assertSnapshotIds(result, 3); - } - - @Test - public void filterOnDateIncludesTime() throws ParseException { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse("2008-12-25 03:00"); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setDateCriterion(new DateCriterion("<", date))); - assertSnapshotIds(result, 2, 4); - } - - @Test - public void filterOnBaseSnapshot() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setPath(2, 2, "")); - assertSnapshotIds(result, 4); - } - - @Test - public void sortByName() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setSortedByName()); - assertSortedSnapshotIds(result, 2, 4, 3); - } - - @Test - public void sortByKey() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setSortedByKey()); - assertSortedSnapshotIds(result, 3, 2, 4); - } - - @Test - public void sortByDate() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setSortedByDate()); - assertSortedSnapshotIds(result, 2, 4, 3); - } - - @Test - public void sortByDescendingDate() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setSortedByDate().setAscendingSort(false)); - assertSortedSnapshotIds(result, 3, 4, 2); - } - - @Test - public void sortByAscendingDate() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setSortedByDate().setAscendingSort(true)); - assertSortedSnapshotIds(result, 2, 4, 3); - } - - @Test - public void sortByAscendingMeasureValue() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .setSortedMetricId(2, true, false); - - FilterResult result = executor.execute(filter); - assertSortedSnapshotIds(result, 6, 5); - } - - @Test - public void sortByDecendingMeasureValue() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .setSortedMetricId(2, true, false) - .setAscendingSort(false); - - FilterResult result = executor.execute(filter); - assertSortedSnapshotIds(result, 5, 6); - } - - @Test - public void applySingleMeasureCriterion() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(2, ">", 50.0, false)); - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 5); - } - - @Test - public void applyManyMeasureCriteria() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(2, ">", 50.0, false)) - .addMeasureCriterion(new MeasureCriterion(1, ">", 100.0, false)); - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 5); - } - - @Test - public void criteriaAreExclusive() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(2, ">", 50.0, false)) - .addMeasureCriterion(new MeasureCriterion(1, "<", 100.0, false)); - - FilterResult result = executor.execute(filter); - assertThat(result.size()).isEqualTo(0); - } - - @Test - public void sortAndFilterMeasures() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(2, ">", 5.0, false)) - .addMeasureCriterion(new MeasureCriterion(1, ">", 5.0, false)) - .setSortedMetricId(2, true, false); // sort by coverage - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 6, 5); - } - - @Test - public void sortDescendingAndFilterMeasures() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(2, ">", 5.0, false)) // filter on coverage - .addMeasureCriterion(new MeasureCriterion(1, ">", 5.0, false)) // filter on lines - .setSortedMetricId(2, true, false) // sort by coverage - .setAscendingSort(false); - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 5, 6); - } - - @Test - public void filterByResourceKey() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setKeyRegexp("*:org.sonar.*")); - assertSnapshotIds(result, 4); - } - - @Test - public void filterByResourceKeyIsCaseInsensitive() { - setupData("shared"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - FilterResult result = executor.execute(Filter.createForAllQualifiers().setKeyRegexp("*:ORG.SonAR.*")); - assertSnapshotIds(result, 4); - } - - @Test - public void filterByMissingMeasureValue() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(3, ">", 0.0, false)); // filter on duplicated lines - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 6); - } - - @Test - public void filterByMissingMeasureValues() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(1, ">", 0.0, false)) // filter on lines - .addMeasureCriterion(new MeasureCriterion(3, ">", 0.0, false)); // filter on duplicated lines - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 6); - } - - @Test - public void sortByMissingMeasureValue() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .setSortedMetricId(3, true, false); // sort by duplicated lines - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 5, 6); - } - - @Test - public void filterByMeasureValueAndSortOnOtherMetric() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(1, ">", 0.0, false)) // lines > 0 - .setSortedMetricId(2, true, false); // sort by coverage - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 6, 5); - } - - @Test - public void intersectionOfCriteriaOnSameMetric() { - setupData("shared", "measures"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.CLASS)) - .addMeasureCriterion(new MeasureCriterion(1, ">", 400.0, false)) // lines > 400 - .addMeasureCriterion(new MeasureCriterion(1, "<", 600.0, false)); // lines > 400 - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 5); - } - - @Test - public void ignoreProjectCopiesOfViews() { - setupData("views"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setQualifiers(Sets.newHashSet(Qualifiers.PROJECT)); - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 1); // the "project copy" with id 4 is ignored - } - - @Test - public void loadProjectCopiesIfPathIsAView() { - setupData("views"); - FilterExecutor executor = new FilterExecutor(getSession(), new H2()); - Filter filter = new Filter() - .setPath(2, 2, "") - .setQualifiers(Sets.newHashSet(Qualifiers.SUBVIEW, Qualifiers.PROJECT)); - - FilterResult result = executor.execute(filter); - assertSnapshotIds(result, 3, 4); - } - - @Test - public void explicitelyUseIndexOnMsSql() { - Filter filter = new Filter().addMeasureCriterion(new MeasureCriterion(1, ">", 400.0, false)); - - String sql = new FilterExecutor(getSession(), new MsSql()).toSql(filter); - assertThat(sql).contains(" WITH (INDEX(measures_sid_metric)) "); - - sql = new FilterExecutor(getSession(), new H2()).toSql(filter); - assertThat(sql).doesNotContain(" WITH (INDEX(measures_sid_metric)) "); - } - - private void assertSnapshotIds(FilterResult result, int... snapshotIds) { - assertThat(result.size()).isEqualTo(snapshotIds.length); - for (int snapshotId : snapshotIds) { - boolean found = false; - for (Object[] row : result.getRows()) { - found |= result.getSnapshotId(row) == snapshotId; - } - if (!found) { - fail("Snapshot id not found in results: " + snapshotId); - } - } - } - - private void assertSortedSnapshotIds(FilterResult result, int... snapshotIds) { - assertThat(result.size()).isEqualTo(snapshotIds.length); - for (int index = 0; index < snapshotIds.length; index++) { - assertThat(result.getSnapshotId(result.getRows().get(index))).isEqualTo(snapshotIds[index]); - } - } -} diff --git a/sonar-server/src/test/java/org/sonar/server/filters/FilterResultTest.java b/sonar-server/src/test/java/org/sonar/server/filters/FilterResultTest.java deleted file mode 100644 index afb3565a7fe..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/filters/FilterResultTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.server.filters; - -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; - -public class FilterResultTest { - - @Test - public void sortWithNullElements() { - List<String[]> list = Arrays.asList(new String[]{"foo"}, new String[]{null}, new String[]{"bar"}, new String[]{null}, new String[]{null}, new String[]{"toto"}); - Collections.sort(list, new FilterResult.NumericComparator(0)); - - assertThat(list.get(0)[0], nullValue()); - assertThat(list.get(1)[0], nullValue()); - assertThat(list.get(2)[0], nullValue()); - assertThat(list.get(3)[0], is("bar")); - assertThat(list.get(4)[0], is("foo")); - assertThat(list.get(5)[0], is("toto")); - } -} diff --git a/sonar-server/src/test/resources/org/sonar/server/filters/FilterExecutorTest/measures.xml b/sonar-server/src/test/resources/org/sonar/server/filters/FilterExecutorTest/measures.xml deleted file mode 100644 index 73a9937f781..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/filters/FilterExecutorTest/measures.xml +++ /dev/null @@ -1,68 +0,0 @@ -<dataset> - <metrics delete_historical_data="[null]" 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"/> - - <metrics delete_historical_data="[null]" id="2" name="coverage" val_type="PERCENT" description="Coverage" domain="Tests" - short_name="Coverage" qualitative="true" user_managed="false" enabled="true" origin="JAV" worst_value="[null]" - optimized_best_value="[null]" best_value="[null]" direction="1" hidden="false"/> - - <metrics delete_historical_data="[null]" id="3" name="duplicated_lines" val_type="INT" description="Duplicated lines" domain="Duplications" - short_name="Duplications" qualitative="false" user_managed="false" enabled="true" origin="JAV" worst_value="[null]" - optimized_best_value="[null]" best_value="[null]" direction="1" hidden="false"/> - - - <!-- Java classes --> - <projects long_name="org.sonar.foo:File1" id="4" scope="FIL" kee="project:java:org.sonar.foo:File1" qualifier="CLA" name="File1" - root_id="1" - description="[null]" enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/> - - <projects long_name="org.sonar.foo:File2" id="5" scope="FIL" kee="project:java:org.sonar.foo:File2" qualifier="CLA" name="File2" - root_id="1" - description="[null]" enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/> - - - <snapshots 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]" id="5" created_at="2008-12-25 01:00:01.00" build_date="2008-12-25 01:00:01.00" version="1.0" project_id="4" scope="FIL" qualifier="CLA" - root_project_id="1" root_snapshot_id="2" parent_snapshot_id="4" STATUS="P" ISLAST="true" - path="2.4." - depth="2"/> - - <snapshots 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]" id="6" created_at="2008-12-25 01:00:01.00" build_date="2008-12-25 01:00:01.00" version="1.0" project_id="5" scope="FIL" qualifier="CLA" - root_project_id="1" root_snapshot_id="2" parent_snapshot_id="4" STATUS="P" ISLAST="true" - path="2.4." - depth="2"/> - - - <!-- SNAPSHOT 5 : 500 lines and coverage 80.5% --> - <project_measures characteristic_id="[null]" id="1" metric_id="1" value="500" snapshot_id="5" - 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]"/> - - <project_measures characteristic_id="[null]" id="2" metric_id="2" value="80.5" snapshot_id="5" - 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]"/> - - - <!-- SNAPSHOT 6 : 30 lines, coverage 20.6% and 10 duplicated lines --> - <project_measures characteristic_id="[null]" id="3" metric_id="1" value="30" snapshot_id="6" - 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]"/> - - <project_measures characteristic_id="[null]" id="4" metric_id="2" value="20.6" snapshot_id="6" - 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]"/> - - <project_measures characteristic_id="[null]" id="5" metric_id="3" value="10" snapshot_id="6" - 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]"/> -</dataset>
\ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/filters/FilterExecutorTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/filters/FilterExecutorTest/shared.xml deleted file mode 100644 index cdb51032ca9..00000000000 --- a/sonar-server/src/test/resources/org/sonar/server/filters/FilterExecutorTest/shared.xml +++ /dev/null @@ -1,39 +0,0 @@ -<dataset> - <projects long_name="java project" id="1" scope="PRJ" kee="project:java" qualifier="TRK" name="java project" - root_id="[null]" - description="[null]" enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/> - - <projects long_name="php project" id="2" scope="PRJ" kee="project:a-php-project" qualifier="TRK" name="php project" - root_id="[null]" - description="[null]" enabled="true" language="php" copy_resource_id="[null]" person_id="[null]"/> - - <projects long_name="org.sonar.foo" id="3" scope="DIR" kee="project:java:org.sonar.foo" qualifier="PAC" name="org.sonar.foo" - root_id="1" - description="[null]" enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/> - - - <!-- Java project --> - <snapshots 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]" id="1" created_at="2008-12-20 00:00:00.00" build_date="2008-12-20 00:00:00.00" version="1.0" project_id="1" scope="PRJ" qualifier="TRK" - root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]" STATUS="P" ISLAST="false" - path="" - depth="0"/> - - <snapshots 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]" id="2" created_at="2008-12-25 01:00:00.00" build_date="2008-12-25 01:00:00.00" version="1.0" project_id="1" scope="PRJ" qualifier="TRK" - root_project_id="1" root_snapshot_id="[null]" parent_snapshot_id="[null]" STATUS="P" ISLAST="true" - path="" - depth="0"/> - - <!-- PHP project --> - <snapshots 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]" id="3" created_at="2008-12-31 02:00:00.00" build_date="2008-12-31 02:00:00.00" version="1.0" project_id="2" scope="PRJ" qualifier="TRK" - root_project_id="2" root_snapshot_id="[null]" parent_snapshot_id="[null]" STATUS="P" ISLAST="true" - path="" - depth="0"/> - - <!-- Java package --> - <snapshots 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]" id="4" created_at="2008-12-25 01:00:01.00" build_date="2008-12-25 01:00:01.00" version="1.0" project_id="3" scope="DIR" qualifier="PAC" - root_project_id="1" root_snapshot_id="2" parent_snapshot_id="2" STATUS="P" ISLAST="true" - path="2." - depth="1"/> - - -</dataset>
\ No newline at end of file |