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<>();
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<>();
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  /**
208   * @deprecated since 5.2. The measures related to rules are computed on server side by Compute Engine.
209   */
210  @Deprecated
211  private abstract static class AbstractRuleMeasureFilter<M> extends MetricFilter<M> {
212    protected AbstractRuleMeasureFilter(Metric metric) {
213      super(metric);
214    }
215
216    private boolean apply(Measure measure) {
217      return measure instanceof RuleMeasure
218        && filterOnMetricKey().equals(measure.getMetricKey())
219        && measure.getPersonId() == null
220        && doApply((RuleMeasure) measure);
221    }
222
223    abstract boolean doApply(RuleMeasure ruleMeasure);
224
225    @Override
226    public M filter(Collection<Measure> measures) {
227      if (measures == null) {
228        return null;
229      }
230      for (Measure measure : measures) {
231        if (apply(measure)) {
232          return (M) measure;
233        }
234      }
235      return null;
236    }
237  }
238
239  /**
240   * @deprecated since 5.2. Useless by design because of Compute Engine
241   */
242  @Deprecated
243  private static class RuleFilter extends AbstractRuleMeasureFilter<RuleMeasure> {
244    private RuleKey ruleKey;
245
246    protected RuleFilter(Metric metric, RuleKey ruleKey) {
247      super(metric);
248      this.ruleKey = ruleKey;
249    }
250
251    @Override
252    boolean doApply(RuleMeasure measure) {
253      return measure.ruleKey() != null
254        && ruleKey.equals(measure.ruleKey());
255    }
256  }
257}