001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2013 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.measures;
021
022import org.sonar.api.rules.Rule;
023import org.sonar.api.technicaldebt.batch.Characteristic;
024import org.sonar.api.technicaldebt.batch.Requirement;
025
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.Collections;
029import java.util.List;
030
031/**
032 * @since 1.10
033 */
034public final class MeasuresFilters {
035
036  private MeasuresFilters() {
037  }
038
039  public static MeasuresFilter<Collection<Measure>> all() {
040    return new MeasuresFilter<Collection<Measure>>() {
041      public Collection<Measure> filter(Collection<Measure> measures) {
042        return measures;
043      }
044    };
045  }
046
047  public static MeasuresFilter<Measure> metric(final Metric metric) {
048    return metric(metric.getKey());
049  }
050
051  public static MeasuresFilter<Measure> metric(final String metricKey) {
052    return new MetricFilter<Measure>(metricKey) {
053
054      public Measure filter(Collection<Measure> measures) {
055        if (measures == null) {
056          return null;
057        }
058        for (Measure measure : measures) {
059          if (measure.getClass().equals(Measure.class) &&
060            measure.getMetricKey().equals(metricKey) &&
061            measure.getCharacteristic() == null &&
062            measure.getPersonId() == null) {
063            return measure;
064          }
065        }
066        return null;
067      }
068    };
069  }
070
071  public static MeasuresFilter<Measure> characteristic(final Metric metric, final Characteristic characteristic) {
072    return new MetricFilter<Measure>(metric) {
073
074      public Measure filter(Collection<Measure> measures) {
075        if (measures == null) {
076          return null;
077        }
078        for (Measure measure : measures) {
079          if (measure.getClass().equals(Measure.class) &&
080            measure.getMetric().equals(metric) &&
081            measure.getPersonId() == null &&
082            isSameCharacteristic(measure, characteristic)) {
083            return measure;
084          }
085        }
086        return null;
087      }
088    };
089  }
090
091  private static boolean isSameCharacteristic(Measure measure, final Characteristic characteristic){
092    Characteristic measureCharacteristic = measure.getCharacteristic();
093    return measureCharacteristic != null &&
094      measureCharacteristic.equals(characteristic);
095  }
096
097  public static MeasuresFilter<Measure> requirement(final Metric metric, final Requirement requirement) {
098    return new MetricFilter<Measure>(metric) {
099
100      public Measure filter(Collection<Measure> measures) {
101        if (measures == null) {
102          return null;
103        }
104        for (Measure measure : measures) {
105          if (measure.getClass().equals(Measure.class) &&
106            measure.getMetric().equals(metric) &&
107            measure.getPersonId() == null &&
108            isSameRequirement(measure, requirement)) {
109            return measure;
110          }
111        }
112        return null;
113      }
114    };
115  }
116
117  private static boolean isSameRequirement(Measure measure, final Requirement requirement){
118    Requirement measureRequirement = measure.getRequirement();
119    return measureRequirement != null &&
120      measureRequirement.equals(requirement);
121  }
122
123  /**
124   * @since 2.0
125   */
126  public static MeasuresFilter<Measure> measure(final Measure measure) {
127    return new MeasuresFilter<Measure>() {
128      public Measure filter(Collection<Measure> measures) {
129        if (measures == null) {
130          return null;
131        }
132        for (Measure m : measures) {
133          if (m.equals(measure)) {
134            return m;
135          }
136        }
137        return null;
138      }
139    };
140  }
141
142  /**
143   * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2007
144   */
145  @Deprecated
146  public static MeasuresFilter<RuleMeasure> ruleCategory(final Metric metric, final Integer category) {
147    return new RuleCategoryFilter(metric, category);
148  }
149
150  public static MeasuresFilter<RuleMeasure> rule(final Metric metric, final Rule rule) {
151    return new RuleFilter(metric, rule);
152  }
153
154  /**
155   * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2007
156   */
157  @Deprecated
158  public static MeasuresFilter<Collection<RuleMeasure>> ruleCategories(final Metric metric) {
159    return new MetricFilter<Collection<RuleMeasure>>(metric) {
160
161      public Collection<RuleMeasure> filter(Collection<Measure> measures) {
162        return Collections.emptyList();
163      }
164    };
165  }
166
167  public static MeasuresFilter<Collection<RuleMeasure>> rules(final Metric metric) {
168    return new MetricFilter<Collection<RuleMeasure>>(metric) {
169
170      private boolean apply(Measure measure) {
171        return measure instanceof RuleMeasure && metric.equals(measure.getMetric())
172          && measure.getPersonId() == null && ((RuleMeasure) measure).getRule() != null;
173      }
174
175      public Collection<RuleMeasure> filter(Collection<Measure> measures) {
176        if (measures == null) {
177          return null;
178        }
179        List<RuleMeasure> result = new ArrayList<RuleMeasure>();
180        for (Measure measure : measures) {
181          if (apply(measure)) {
182            result.add((RuleMeasure) measure);
183          }
184        }
185        return result;
186      }
187    };
188  }
189
190  /**
191   * Used for internal optimizations.
192   */
193  public abstract static class MetricFilter<M> implements MeasuresFilter<M> {
194    private final String metricKey;
195
196    protected MetricFilter(Metric metric) {
197      this.metricKey = metric.getKey();
198    }
199
200    protected MetricFilter(String metricKey) {
201      this.metricKey = metricKey;
202    }
203
204    public String filterOnMetricKey() {
205      return metricKey;
206    }
207  }
208
209  private abstract static class AbstractRuleMeasureFilter<M> extends MetricFilter<M> {
210    protected AbstractRuleMeasureFilter(Metric metric) {
211      super(metric);
212    }
213
214    private boolean apply(Measure measure) {
215      return measure instanceof RuleMeasure
216        && filterOnMetricKey().equals(measure.getMetricKey())
217        && measure.getPersonId() == null
218        && doApply((RuleMeasure) measure);
219    }
220
221    abstract boolean doApply(RuleMeasure ruleMeasure);
222
223    public M filter(Collection<Measure> measures) {
224      if (measures == null) {
225        return null;
226      }
227      for (Measure measure : measures) {
228        if (apply(measure)) {
229          return (M) measure;
230        }
231      }
232      return null;
233    }
234  }
235
236  /**
237   * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2007
238   */
239  @Deprecated
240  private static class RuleCategoryFilter extends AbstractRuleMeasureFilter<RuleMeasure> {
241
242    protected RuleCategoryFilter(Metric metric, Integer categ) {
243      super(metric);
244    }
245
246    @Override
247    boolean doApply(RuleMeasure measure) {
248      return false;
249    }
250  }
251
252
253  private static class RuleFilter extends AbstractRuleMeasureFilter<RuleMeasure> {
254    private Rule rule;
255
256    protected RuleFilter(Metric metric, Rule rule) {
257      super(metric);
258      this.rule = rule;
259    }
260
261    @Override
262    boolean doApply(RuleMeasure measure) {
263      return measure.getRule() != null
264        && rule.equals(measure.getRule());
265    }
266  }
267}