001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 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.rule.RuleKey;
023import org.sonar.api.rules.Rule;
024import org.sonar.api.technicaldebt.batch.Characteristic;
025import org.sonar.api.technicaldebt.batch.Requirement;
026
027import java.util.ArrayList;
028import java.util.Collection;
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      @Override
042      public Collection<Measure> filter(Collection<Measure> measures) {
043        Collection<Measure> all = new ArrayList<Measure>();
044        for (Measure measure : measures) {
045          if (measure != null) {
046            all.add(measure);
047          }
048        }
049        return all;
050      }
051    };
052  }
053
054  public static MeasuresFilter<Measure> metric(final org.sonar.api.batch.measure.Metric<?> metric) {
055    return metric(metric.key());
056  }
057
058  public static MeasuresFilter<Measure> metric(final String metricKey) {
059    return new MetricFilter<Measure>(metricKey) {
060      @Override
061      public Measure filter(Collection<Measure> measures) {
062        if (measures == null) {
063          return null;
064        }
065        for (Measure measure : measures) {
066          if (measure.getClass().equals(Measure.class) &&
067            measure.getMetricKey().equals(metricKey) &&
068            measure.getCharacteristic() == null &&
069            measure.getPersonId() == null) {
070            return measure;
071          }
072        }
073        return null;
074      }
075    };
076  }
077
078  public static MeasuresFilter<Measure> characteristic(final Metric metric, final Characteristic characteristic) {
079    return new MetricFilter<Measure>(metric) {
080
081      @Override
082      public Measure filter(Collection<Measure> measures) {
083        if (measures == null) {
084          return null;
085        }
086        for (Measure measure : measures) {
087          if (measure.getClass().equals(Measure.class) &&
088            measure.getMetric().equals(metric) &&
089            measure.getPersonId() == null &&
090            isSameCharacteristic(measure, characteristic)) {
091            return measure;
092          }
093        }
094        return null;
095      }
096    };
097  }
098
099  private static boolean isSameCharacteristic(Measure measure, final Characteristic characteristic) {
100    Characteristic measureCharacteristic = measure.getCharacteristic();
101    return measureCharacteristic != null &&
102      measureCharacteristic.equals(characteristic);
103  }
104
105  /**
106   * @deprecated since 4.3
107   */
108  @Deprecated
109  public static MeasuresFilter<Measure> requirement(final Metric metric, final Requirement requirement) {
110    return new MetricFilter<Measure>(metric) {
111
112      @Override
113      public Measure filter(Collection<Measure> measures) {
114        if (measures == null) {
115          return null;
116        }
117        for (Measure measure : measures) {
118          if (measure.getClass().equals(Measure.class) &&
119            measure.getMetric().equals(metric) &&
120            measure.getPersonId() == null &&
121            isSameRequirement(measure, requirement)) {
122            return measure;
123          }
124        }
125        return null;
126      }
127    };
128  }
129
130  private static boolean isSameRequirement(Measure measure, final Requirement requirement) {
131    Requirement measureRequirement = measure.getRequirement();
132    return measureRequirement != null &&
133      measureRequirement.equals(requirement);
134  }
135
136  /**
137   * @since 2.0
138   */
139  public static MeasuresFilter<Measure> measure(final Measure measure) {
140    return new MeasuresFilter<Measure>() {
141      @Override
142      public Measure filter(Collection<Measure> measures) {
143        if (measures == null) {
144          return null;
145        }
146        for (Measure m : measures) {
147          if (m.equals(measure)) {
148            return m;
149          }
150        }
151        return null;
152      }
153    };
154  }
155
156  public static MeasuresFilter<RuleMeasure> rule(final Metric metric, final RuleKey ruleKey) {
157    return new RuleFilter(metric, ruleKey);
158  }
159
160  public static MeasuresFilter<RuleMeasure> rule(final Metric metric, final Rule rule) {
161    return rule(metric, rule.ruleKey());
162  }
163
164  public static MeasuresFilter<Collection<RuleMeasure>> rules(final Metric metric) {
165    return new MetricFilter<Collection<RuleMeasure>>(metric) {
166
167      private boolean apply(Measure measure) {
168        return measure instanceof RuleMeasure && metric.equals(measure.getMetric())
169          && measure.getPersonId() == null && ((RuleMeasure) measure).ruleKey() != null;
170      }
171
172      @Override
173      public Collection<RuleMeasure> filter(Collection<Measure> measures) {
174        if (measures == null) {
175          return null;
176        }
177        List<RuleMeasure> result = new ArrayList<RuleMeasure>();
178        for (Measure measure : measures) {
179          if (apply(measure)) {
180            result.add((RuleMeasure) measure);
181          }
182        }
183        return result;
184      }
185    };
186  }
187
188  /**
189   * Used for internal optimizations.
190   */
191  public abstract static class MetricFilter<M> implements MeasuresFilter<M> {
192    private final String metricKey;
193
194    protected MetricFilter(Metric metric) {
195      this.metricKey = metric.getKey();
196    }
197
198    protected MetricFilter(String metricKey) {
199      this.metricKey = metricKey;
200    }
201
202    public String filterOnMetricKey() {
203      return metricKey;
204    }
205  }
206
207  private abstract static class AbstractRuleMeasureFilter<M> extends MetricFilter<M> {
208    protected AbstractRuleMeasureFilter(Metric metric) {
209      super(metric);
210    }
211
212    private boolean apply(Measure measure) {
213      return measure instanceof RuleMeasure
214        && filterOnMetricKey().equals(measure.getMetricKey())
215        && measure.getPersonId() == null
216        && doApply((RuleMeasure) measure);
217    }
218
219    abstract boolean doApply(RuleMeasure ruleMeasure);
220
221    @Override
222    public M filter(Collection<Measure> measures) {
223      if (measures == null) {
224        return null;
225      }
226      for (Measure measure : measures) {
227        if (apply(measure)) {
228          return (M) measure;
229        }
230      }
231      return null;
232    }
233  }
234
235  private static class RuleFilter extends AbstractRuleMeasureFilter<RuleMeasure> {
236    private RuleKey ruleKey;
237
238    protected RuleFilter(Metric metric, RuleKey ruleKey) {
239      super(metric);
240      this.ruleKey = ruleKey;
241    }
242
243    @Override
244    boolean doApply(RuleMeasure measure) {
245      return measure.ruleKey() != null
246        && ruleKey.equals(measure.ruleKey());
247    }
248  }
249}