3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.ce.task.projectanalysis.duplication;
22 import com.google.common.base.Function;
23 import com.google.common.collect.ArrayListMultimap;
24 import com.google.common.collect.Multimap;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import javax.annotation.CheckForNull;
28 import javax.annotation.Nonnull;
29 import org.junit.rules.ExternalResource;
30 import org.sonar.ce.task.projectanalysis.component.Component;
31 import org.sonar.ce.task.projectanalysis.component.ComponentProvider;
32 import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
33 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderComponentProvider;
34 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
36 import static com.google.common.base.Preconditions.checkArgument;
37 import static com.google.common.collect.FluentIterable.from;
38 import static java.util.Objects.requireNonNull;
40 public class DuplicationRepositoryRule extends ExternalResource implements DuplicationRepository {
42 private final ComponentProvider componentProvider;
43 private DuplicationRepositoryImpl delegate;
44 private final Multimap<Component, TextBlock> componentRefsWithInnerDuplications = ArrayListMultimap.create();
45 private final Multimap<Component, TextBlock> componentRefsWithInProjectDuplications = ArrayListMultimap.create();
46 private final Multimap<Component, TextBlock> componentRefsWithCrossProjectDuplications = ArrayListMultimap.create();
48 private DuplicationRepositoryRule(TreeRootHolder treeRootHolder) {
49 this.componentProvider = new TreeRootHolderComponentProvider(treeRootHolder);
52 public DuplicationRepositoryRule() {
53 this.componentProvider = null;
56 public static DuplicationRepositoryRule create(TreeRootHolderRule treeRootHolder) {
57 return new DuplicationRepositoryRule(treeRootHolder);
60 public static DuplicationRepositoryRule create() {
61 return new DuplicationRepositoryRule();
65 protected void before() {
66 this.delegate = new DuplicationRepositoryImpl();
70 protected void after() {
71 if (this.componentProvider != null) {
72 this.componentProvider.reset();
74 this.componentRefsWithInnerDuplications.clear();
75 this.componentRefsWithInProjectDuplications.clear();
76 this.componentRefsWithCrossProjectDuplications.clear();
80 public Iterable<Duplication> getDuplications(int fileRef) {
81 ensureComponentProviderInitialized();
83 return delegate.getDuplications(componentProvider.getByRef(fileRef));
86 public void add(int fileRef, Duplication duplication) {
87 ensureComponentProviderInitialized();
89 delegate.add(componentProvider.getByRef(fileRef), duplication);
92 public DuplicationRepositoryRule addDuplication(int fileRef, TextBlock original, TextBlock... duplicates) {
93 ensureComponentProviderInitialized();
94 Component component = componentProvider.getByRef(fileRef);
95 checkArgument(!componentRefsWithInnerDuplications.containsEntry(component, original), "Inner duplications for file %s and original %s already set", fileRef, original);
96 checkArgument(!componentRefsWithInProjectDuplications.containsEntry(component, original),
97 "InProject duplications for file %s and original %s already set. Use add(int, Duplication) instead", fileRef, original);
99 componentRefsWithInnerDuplications.put(component, original);
104 from(Arrays.asList(duplicates)).transform(TextBlockToInnerDuplicate.INSTANCE)));
109 public DuplicationRepositoryRule addDuplication(int fileRef, TextBlock original, int otherFileRef, TextBlock duplicate) {
110 ensureComponentProviderInitialized();
111 Component component = componentProvider.getByRef(fileRef);
112 checkArgument(!componentRefsWithInProjectDuplications.containsEntry(component, original), "InProject duplications for file %s and original %s already set", fileRef, original);
113 checkArgument(!componentRefsWithInnerDuplications.containsEntry(component, original),
114 "Inner duplications for file %s and original %s already set. Use add(int, Duplication) instead", fileRef, original);
116 componentRefsWithInProjectDuplications.put(component, original);
117 delegate.add(component,
120 Collections.singletonList(new InProjectDuplicate(componentProvider.getByRef(otherFileRef), duplicate))));
125 public DuplicationRepositoryRule addExtendedProjectDuplication(int fileRef, TextBlock original, int otherFileRef, TextBlock duplicate) {
126 ensureComponentProviderInitialized();
127 Component component = componentProvider.getByRef(fileRef);
128 checkArgument(!componentRefsWithCrossProjectDuplications.containsEntry(component, original), "CrossProject duplications for file %s and original %s already set", fileRef);
130 componentRefsWithCrossProjectDuplications.put(component, original);
131 delegate.add(componentProvider.getByRef(fileRef),
134 Collections.singletonList(new InExtendedProjectDuplicate(componentProvider.getByRef(otherFileRef), duplicate))));
139 public DuplicationRepositoryRule addCrossProjectDuplication(int fileRef, TextBlock original, String otherFileKey, TextBlock duplicate) {
140 ensureComponentProviderInitialized();
141 Component component = componentProvider.getByRef(fileRef);
142 checkArgument(!componentRefsWithCrossProjectDuplications.containsEntry(component, original), "CrossProject duplications for file %s and original %s already set", fileRef);
144 componentRefsWithCrossProjectDuplications.put(component, original);
145 delegate.add(componentProvider.getByRef(fileRef),
148 Collections.singletonList(new CrossProjectDuplicate(otherFileKey, duplicate))));
154 public Iterable<Duplication> getDuplications(Component file) {
155 return delegate.getDuplications(file);
159 public void add(Component file, Duplication duplication) {
160 TextBlock original = duplication.getOriginal();
161 checkArgument(!componentRefsWithInnerDuplications.containsEntry(file, original), "Inner duplications for file %s and original %s already set", file, original);
162 checkArgument(!componentRefsWithInProjectDuplications.containsEntry(file, original), "InProject duplications for file %s and original %s already set", file, original);
163 checkArgument(!componentRefsWithCrossProjectDuplications.containsEntry(file, original), "CrossProject duplications for file %s and original %s already set", file, original);
165 delegate.add(file, duplication);
168 private void ensureComponentProviderInitialized() {
169 requireNonNull(this.componentProvider, "Methods with component reference can not be used unless a TreeRootHolder has been provided when instantiating the rule");
170 this.componentProvider.ensureInitialized();
173 private enum TextBlockToInnerDuplicate implements Function<TextBlock, Duplicate> {
178 public Duplicate apply(@Nonnull TextBlock input) {
179 return new InnerDuplicate(input);