]> source.dussan.org Git - sonarqube.git/blob
751a962bf2042d9acb06fd2bb6fe04898ffad81d
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.computation.task.projectanalysis.measure;
21
22 import com.google.common.base.Function;
23 import com.google.common.base.Optional;
24 import com.google.common.base.Predicate;
25 import com.google.common.collect.ImmutableSetMultimap;
26 import com.google.common.collect.SetMultimap;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Set;
32 import javax.annotation.Nonnull;
33 import javax.annotation.Nullable;
34 import org.sonar.server.computation.task.projectanalysis.component.Component;
35 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
36
37 import static com.google.common.base.Preconditions.checkArgument;
38 import static com.google.common.collect.FluentIterable.from;
39 import static java.lang.String.format;
40 import static java.util.Objects.requireNonNull;
41
42 /**
43  * Map based implementation of MeasureRepository which supports only raw measures.
44  *
45  * Intended to be used as a delegate of other MeasureRepository implementations (hence the final keyword).
46  */
47 public final class MapBasedRawMeasureRepository<T> implements MeasureRepository {
48   private final Function<Component, T> componentToKey;
49   private final Map<T, Map<MeasureKey, Measure>> measures = new HashMap<>();
50
51   public MapBasedRawMeasureRepository(Function<Component, T> componentToKey) {
52     this.componentToKey = requireNonNull(componentToKey);
53   }
54
55   /**
56    * @throws UnsupportedOperationException all the time, not supported
57    */
58   @Override
59   public Optional<Measure> getBaseMeasure(Component component, Metric metric) {
60     throw new UnsupportedOperationException("This implementation of MeasureRepository supports only raw measures");
61   }
62
63   @Override
64   public int loadAsRawMeasures(Collection<Component> components, Collection<Metric> metrics) {
65     throw new UnsupportedOperationException("This implementation of MeasureRepository supports only raw measures");
66   }
67
68   @Override
69   public Optional<Measure> getRawMeasure(final Component component, final Metric metric) {
70     // fail fast
71     requireNonNull(component);
72     requireNonNull(metric);
73
74     return find(component, metric);
75   }
76
77   @Override
78   public void add(Component component, Metric metric, Measure measure) {
79     requireNonNull(component);
80     checkValueTypeConsistency(metric, measure);
81
82     Optional<Measure> existingMeasure = find(component, metric, measure);
83     if (existingMeasure.isPresent()) {
84       throw new UnsupportedOperationException(
85         format(
86           "a measure can be set only once for a specific Component (key=%s), Metric (key=%s). Use update method",
87           component.getKey(),
88           metric.getKey()));
89     }
90     add(component, metric, measure, OverridePolicy.OVERRIDE);
91   }
92
93   @Override
94   public void update(Component component, Metric metric, Measure measure) {
95     requireNonNull(component);
96     checkValueTypeConsistency(metric, measure);
97
98     Optional<Measure> existingMeasure = find(component, metric, measure);
99     if (!existingMeasure.isPresent()) {
100       throw new UnsupportedOperationException(
101         format(
102           "a measure can be updated only if one already exists for a specific Component (key=%s), Metric (key=%s). Use add method",
103           component.getKey(),
104           metric.getKey()));
105     }
106     add(component, metric, measure, OverridePolicy.OVERRIDE);
107   }
108
109   private static void checkValueTypeConsistency(Metric metric, Measure measure) {
110     checkArgument(
111       measure.getValueType() == Measure.ValueType.NO_VALUE || measure.getValueType() == metric.getType().getValueType(),
112       "Measure's ValueType (%s) is not consistent with the Metric's ValueType (%s)",
113       measure.getValueType(), metric.getType().getValueType());
114   }
115
116   @Override
117   public Set<Measure> getRawMeasures(Component component, Metric metric) {
118     requireNonNull(metric);
119     requireNonNull(component);
120     T componentKey = componentToKey.apply(component);
121     Map<MeasureKey, Measure> rawMeasures = measures.get(componentKey);
122     if (rawMeasures == null) {
123       return Collections.emptySet();
124     }
125     return from(rawMeasures.entrySet()).filter(new MatchMetric(metric)).transform(ToMeasure.INSTANCE).toSet();
126   }
127
128   @Override
129   public SetMultimap<String, Measure> getRawMeasures(Component component) {
130     T componentKey = componentToKey.apply(component);
131     Map<MeasureKey, Measure> rawMeasures = measures.get(componentKey);
132     if (rawMeasures == null) {
133       return ImmutableSetMultimap.of();
134     }
135
136     ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder();
137     for (Map.Entry<MeasureKey, Measure> entry : rawMeasures.entrySet()) {
138       builder.put(entry.getKey().getMetricKey(), entry.getValue());
139     }
140     return builder.build();
141   }
142
143   private Optional<Measure> find(Component component, Metric metric) {
144     T componentKey = componentToKey.apply(component);
145     Map<MeasureKey, Measure> measuresPerMetric = measures.get(componentKey);
146     if (measuresPerMetric == null) {
147       return Optional.absent();
148     }
149     return Optional.fromNullable(measuresPerMetric.get(new MeasureKey(metric.getKey(), null)));
150   }
151
152   private Optional<Measure> find(Component component, Metric metric, Measure measure) {
153     T componentKey = componentToKey.apply(component);
154     Map<MeasureKey, Measure> measuresPerMetric = measures.get(componentKey);
155     if (measuresPerMetric == null) {
156       return Optional.absent();
157     }
158     return Optional.fromNullable(measuresPerMetric.get(new MeasureKey(metric.getKey(), measure.getDeveloper())));
159   }
160
161   public void add(Component component, Metric metric, Measure measure, OverridePolicy overridePolicy) {
162     requireNonNull(component);
163     requireNonNull(measure);
164     requireNonNull(measure);
165     requireNonNull(overridePolicy);
166
167     T componentKey = componentToKey.apply(component);
168     Map<MeasureKey, Measure> measuresPerMetric = measures.get(componentKey);
169     if (measuresPerMetric == null) {
170       measuresPerMetric = new HashMap<>();
171       measures.put(componentKey, measuresPerMetric);
172     }
173     MeasureKey key = new MeasureKey(metric.getKey(), measure.getDeveloper());
174     if (!measuresPerMetric.containsKey(key) || overridePolicy == OverridePolicy.OVERRIDE) {
175       measuresPerMetric.put(key, measure);
176     }
177   }
178
179   public enum OverridePolicy {
180     OVERRIDE, DO_NOT_OVERRIDE
181   }
182
183   private static class MatchMetric implements Predicate<Map.Entry<MeasureKey, Measure>> {
184     private final Metric metric;
185
186     public MatchMetric(Metric metric) {
187       this.metric = metric;
188     }
189
190     @Override
191     public boolean apply(@Nonnull Map.Entry<MeasureKey, Measure> input) {
192       return input.getKey().getMetricKey().equals(metric.getKey());
193     }
194   }
195
196   private enum ToMeasure implements Function<Map.Entry<MeasureKey, Measure>, Measure> {
197     INSTANCE;
198
199     @Nullable
200     @Override
201     public Measure apply(@Nonnull Map.Entry<MeasureKey, Measure> input) {
202       return input.getValue();
203     }
204   }
205 }