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 Rule rule) {
157        return new RuleFilter(metric, rule.ruleKey());
158      }
159    
160      public static MeasuresFilter<Collection<RuleMeasure>> rules(final Metric metric) {
161        return new MetricFilter<Collection<RuleMeasure>>(metric) {
162    
163          private boolean apply(Measure measure) {
164            return measure instanceof RuleMeasure && metric.equals(measure.getMetric())
165              && measure.getPersonId() == null && ((RuleMeasure) measure).ruleKey() != null;
166          }
167    
168          @Override
169          public Collection<RuleMeasure> filter(Collection<Measure> measures) {
170            if (measures == null) {
171              return null;
172            }
173            List<RuleMeasure> result = new ArrayList<RuleMeasure>();
174            for (Measure measure : measures) {
175              if (apply(measure)) {
176                result.add((RuleMeasure) measure);
177              }
178            }
179            return result;
180          }
181        };
182      }
183    
184      /**
185       * Used for internal optimizations.
186       */
187      public abstract static class MetricFilter<M> implements MeasuresFilter<M> {
188        private final String metricKey;
189    
190        protected MetricFilter(Metric metric) {
191          this.metricKey = metric.getKey();
192        }
193    
194        protected MetricFilter(String metricKey) {
195          this.metricKey = metricKey;
196        }
197    
198        public String filterOnMetricKey() {
199          return metricKey;
200        }
201      }
202    
203      private abstract static class AbstractRuleMeasureFilter<M> extends MetricFilter<M> {
204        protected AbstractRuleMeasureFilter(Metric metric) {
205          super(metric);
206        }
207    
208        private boolean apply(Measure measure) {
209          return measure instanceof RuleMeasure
210            && filterOnMetricKey().equals(measure.getMetricKey())
211            && measure.getPersonId() == null
212            && doApply((RuleMeasure) measure);
213        }
214    
215        abstract boolean doApply(RuleMeasure ruleMeasure);
216    
217        @Override
218        public M filter(Collection<Measure> measures) {
219          if (measures == null) {
220            return null;
221          }
222          for (Measure measure : measures) {
223            if (apply(measure)) {
224              return (M) measure;
225            }
226          }
227          return null;
228        }
229      }
230    
231      private static class RuleFilter extends AbstractRuleMeasureFilter<RuleMeasure> {
232        private RuleKey ruleKey;
233    
234        protected RuleFilter(Metric metric, RuleKey ruleKey) {
235          super(metric);
236          this.ruleKey = ruleKey;
237        }
238    
239        @Override
240        boolean doApply(RuleMeasure measure) {
241          return measure.ruleKey() != null
242            && ruleKey.equals(measure.ruleKey());
243        }
244      }
245    }