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     */
020    package org.sonar.api.measures;
021    
022    import org.sonar.api.rule.RuleKey;
023    import org.sonar.api.rules.Rule;
024    import org.sonar.api.technicaldebt.batch.Characteristic;
025    import org.sonar.api.technicaldebt.batch.Requirement;
026    
027    import java.util.ArrayList;
028    import java.util.Collection;
029    import java.util.List;
030    
031    /**
032     * @since 1.10
033     */
034    public 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    }