]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6990 merge ReportTreeRootHolder into TreeRootHolder
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 9 Nov 2015 09:49:46 +0000 (10:49 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 9 Nov 2015 15:34:20 +0000 (16:34 +0100)
+ add methods to get Component by key from TreeRootHolder

16 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/component/MutableTreeRootHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/component/ReportTreeRootHolder.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/component/ReportTreeRootHolderImpl.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/component/MutableTreeRootHolderRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/component/ReportTreeRootHolderImplTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/component/TreeRootHolderImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStepTest.java

index cfb79c72184a82afe8b404168252ed0257cbdee0..4fb9331412eb0be96d7602eea4369d8e50b71e34 100644 (file)
@@ -28,6 +28,7 @@ public interface MutableTreeRootHolder extends TreeRootHolder {
    * @param newRoot a {@link Component}, can not be {@code null}
    *                
    * @throws NullPointerException if {@code newRoot} is {@code null}
+   * @throws IllegalStateException if root {@link Component} has already been set
    */
   MutableTreeRootHolder setRoot(Component newRoot);
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ReportTreeRootHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ReportTreeRootHolder.java
deleted file mode 100644 (file)
index d33c264..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.component;
-
-public interface ReportTreeRootHolder extends TreeRootHolder {
-
-  /**
-   * Return a component by its batch reference
-   *
-   * @throws IllegalStateException if the holder is empty (ie. there is no root yet)
-   * @throws IllegalArgumentException if there's no component for the reference
-   */
-  Component getComponentByRef(int ref);
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ReportTreeRootHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ReportTreeRootHolderImpl.java
deleted file mode 100644 (file)
index 5a6e944..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.component;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
-
-public class ReportTreeRootHolderImpl extends TreeRootHolderImpl implements ReportTreeRootHolder {
-  private Map<Integer, Component> componentsByRef = new HashMap<>();
-
-  @Override
-  public MutableTreeRootHolder setRoot(Component newRoot) {
-    super.setRoot(newRoot);
-    feedComponentsByRef(newRoot);
-    return this;
-  }
-
-  private void feedComponentsByRef(Component newRoot) {
-    new DepthTraversalTypeAwareCrawler(
-      new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, POST_ORDER) {
-        @Override
-        public void visitAny(Component component) {
-          componentsByRef.put(component.getReportAttributes().getRef(), component);
-        }
-      }).visit(newRoot);
-  }
-
-  @Override
-  public Component getComponentByRef(int ref) {
-    // makes sure the root is set, hence componentsByRef is populated
-    getRoot();
-    Component component = componentsByRef.get(ref);
-    checkArgument(component != null, String.format("Component '%s' hasn't been found", ref));
-    return component;
-  }
-}
index 4b990fc9845178891c081f2546a12ac3f6efee35..59b3c327883f978c38aaf4b358454338b7d829da 100644 (file)
@@ -26,4 +26,29 @@ public interface TreeRootHolder {
    * @throws IllegalStateException if the holder is empty (ie. there is no root yet)
    */
   Component getRoot();
+
+  /**
+   * Return a component by its batch reference
+   *
+   * @throws IllegalStateException if the holder is empty (ie. there is no root yet)
+   * @throws IllegalArgumentException if there's no {@link Component} with the specified reference
+   */
+  Component getComponentByRef(int ref);
+
+  /**
+   * Retrieves the component with the specified key in the {@link Component} tree in the holder.
+   *
+   * @throws NullPointerException if {@code key} is {@code null}
+   * @throws IllegalStateException if the holder is empty (ie. there is not root  yet)
+   * @throws IllegalArgumentException if there is no {@link Component} with the specified key in the tree
+   */
+  Component getComponentByKey(String key);
+
+  /**
+   * Checks whether the {@link Component} with the specified key exists in the tree.
+   * 
+   * @throws NullPointerException if {@code key} is {@code null}
+   * @throws IllegalStateException if the holder is empty (ie. there is not root  yet)
+   */
+  boolean hasComponentWithKey(String key);
 }
index 21588209a1e740224d6df387b3d7793aae755b26..1e410a5b80c01b739761f250bdcf7c2dbc0bd944 100644 (file)
  */
 package org.sonar.server.computation.component;
 
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
 
 /**
  * Holds the reference to the root of the {@link Component} tree for the current CE run.
  */
 public class TreeRootHolderImpl implements MutableTreeRootHolder {
+  @CheckForNull
+  private Map<Integer, Component> componentsByRef;
+  @CheckForNull
+  private Map<String, Component> componentsByKey;
 
   private Component root;
 
   @Override
-  public MutableTreeRootHolder setRoot(Component newRoot) {
-    this.root = requireNonNull(newRoot);
+  public MutableTreeRootHolder setRoot(Component root) {
+    checkState(this.root == null, "root can not be set twice in holder");
+    this.root = requireNonNull(root, "root can not be null");
     return this;
   }
 
   @Override
   public Component getRoot() {
-    checkState(this.root != null, "Root has not been created yet");
+    checkInitialized();
     return this.root;
   }
 
+  @Override
+  public Component getComponentByRef(int ref) {
+    checkInitialized();
+    ensureComponentByRefIsPopulated();
+    Component component = componentsByRef.get(ref);
+    checkArgument(component != null, "Component with ref '%s' can't be found", ref);
+    return component;
+  }
+
+  private void ensureComponentByRefIsPopulated() {
+    if (componentsByRef != null) {
+      return;
+    }
+
+    final ImmutableMap.Builder<Integer, Component> builder = ImmutableMap.builder();
+    new DepthTraversalTypeAwareCrawler(
+      new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, POST_ORDER) {
+        @Override
+        public void visitAny(Component component) {
+          builder.put(component.getReportAttributes().getRef(), component);
+        }
+      }).visit(this.root);
+    this.componentsByRef = builder.build();
+  }
+
+  @Override
+  public Component getComponentByKey(String key) {
+    checkKeyArgument(key);
+    checkInitialized();
+    ensureComponentByKeyIsPopulated();
+    Component component = componentsByKey.get(key);
+    checkArgument(component != null, "Component with key '%s' can't be found", key);
+    return component;
+  }
+
+  @Override
+  public boolean hasComponentWithKey(String key) {
+    checkKeyArgument(key);
+    checkInitialized();
+    ensureComponentByKeyIsPopulated();
+
+    return componentsByKey.containsKey(key);
+  }
+
+  private void checkInitialized() {
+    checkState(this.root != null, "Holder has not been initialized yet");
+  }
+
+  private static void checkKeyArgument(String key) {
+    requireNonNull(key, "key can not be null");
+  }
+
+  private void ensureComponentByKeyIsPopulated() {
+    if (componentsByKey != null) {
+      return;
+    }
+
+    final ImmutableMap.Builder<String, Component> builder = ImmutableMap.builder();
+    new DepthTraversalTypeAwareCrawler(
+      new TypeAwareVisitorAdapter(CrawlerDepthLimit.LEAVES, POST_ORDER) {
+        @Override
+        public void visitAny(Component component) {
+          builder.put(component.getKey(), component);
+        }
+      }).visit(this.root);
+    this.componentsByKey = builder.build();
+  }
 }
index f74ac8ba1eca06bd1a65c62789356c10103e5014..b625ee51faf7b3901187f6ad9b24b899ba2aad2b 100644 (file)
@@ -27,8 +27,8 @@ import org.sonar.server.computation.analysis.AnalysisMetadataHolderImpl;
 import org.sonar.server.computation.batch.BatchReportDirectoryHolderImpl;
 import org.sonar.server.computation.batch.BatchReportReaderImpl;
 import org.sonar.server.computation.component.DbIdsRepositoryImpl;
-import org.sonar.server.computation.component.ReportTreeRootHolderImpl;
 import org.sonar.server.computation.component.SettingsRepositoryImpl;
+import org.sonar.server.computation.component.TreeRootHolderImpl;
 import org.sonar.server.computation.debt.DebtModelHolderImpl;
 import org.sonar.server.computation.duplication.DuplicationRepositoryImpl;
 import org.sonar.server.computation.event.EventRepositoryImpl;
@@ -117,7 +117,7 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop
       // holders
       AnalysisMetadataHolderImpl.class,
       BatchReportDirectoryHolderImpl.class,
-      ReportTreeRootHolderImpl.class,
+      TreeRootHolderImpl.class,
       PeriodsHolderImpl.class,
       QualityGateHolderImpl.class,
       DebtModelHolderImpl.class,
index fca45414d4c71c524d731ea546343acbb9834e74..053a71d81d86d23e76f1d09938ca5215aac9eb7d 100644 (file)
@@ -19,6 +19,9 @@
  */
 package org.sonar.server.computation.issue;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.log.Loggers;
@@ -32,25 +35,21 @@ import org.sonar.db.protobuf.DbCommons;
 import org.sonar.db.protobuf.DbIssues;
 import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.ReportTreeRootHolder;
+import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.issue.commonrule.CommonRuleEngine;
 import org.sonar.server.computation.source.SourceLinesRepository;
 import org.sonar.server.rule.CommonRuleKeys;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 import static com.google.common.collect.Lists.newArrayList;
 
 public class TrackerRawInputFactory {
 
-  private final ReportTreeRootHolder treeRootHolder;
+  private final TreeRootHolder treeRootHolder;
   private final BatchReportReader reportReader;
   private final SourceLinesRepository sourceLinesRepository;
   private final CommonRuleEngine commonRuleEngine;
 
-  public TrackerRawInputFactory(ReportTreeRootHolder treeRootHolder, BatchReportReader reportReader,
+  public TrackerRawInputFactory(TreeRootHolder treeRootHolder, BatchReportReader reportReader,
     SourceLinesRepository sourceLinesRepository, CommonRuleEngine commonRuleEngine) {
     this.treeRootHolder = treeRootHolder;
     this.reportReader = reportReader;
index 8fea5413b158c9c9f79dd236cbbbafc61fb84cb9..3006266bfc2828cd6423fb8b35c39b7b98587282 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.CrawlerDepthLimit;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
-import org.sonar.server.computation.component.ReportTreeRootHolder;
+import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.component.TypeAwareVisitorAdapter;
 import org.sonar.server.computation.duplication.DuplicationRepository;
 import org.sonar.server.computation.duplication.TextBlock;
@@ -36,11 +36,11 @@ import static org.sonar.server.computation.component.ComponentVisitor.Order.POST
  * Loads duplication information from the report and loads them into the {@link DuplicationRepository}.
  */
 public class LoadDuplicationsFromReportStep implements ComputationStep {
-  private final ReportTreeRootHolder treeRootHolder;
+  private final TreeRootHolder treeRootHolder;
   private final BatchReportReader batchReportReader;
   private final DuplicationRepository duplicationRepository;
 
-  public LoadDuplicationsFromReportStep(ReportTreeRootHolder treeRootHolder, BatchReportReader batchReportReader, DuplicationRepository duplicationRepository) {
+  public LoadDuplicationsFromReportStep(TreeRootHolder treeRootHolder, BatchReportReader batchReportReader, DuplicationRepository duplicationRepository) {
     this.treeRootHolder = treeRootHolder;
     this.batchReportReader = batchReportReader;
     this.duplicationRepository = duplicationRepository;
index 74671bcbae444094ebeb048ff3ce8132e9934637..901df0b3347647dd452baeedc3513e2ef88e6e4f 100644 (file)
@@ -32,7 +32,7 @@ import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.CrawlerDepthLimit;
 import org.sonar.server.computation.component.DbIdsRepository;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
-import org.sonar.server.computation.component.ReportTreeRootHolder;
+import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.component.TypeAwareVisitorAdapter;
 import org.sonar.server.computation.duplication.CrossProjectDuplicate;
 import org.sonar.server.computation.duplication.Duplicate;
@@ -51,11 +51,11 @@ public class PersistDuplicationsStep implements ComputationStep {
 
   private final DbClient dbClient;
   private final DbIdsRepository dbIdsRepository;
-  private final ReportTreeRootHolder treeRootHolder;
+  private final TreeRootHolder treeRootHolder;
   private final DuplicationRepository duplicationRepository;
 
-  public PersistDuplicationsStep(DbClient dbClient, DbIdsRepository dbIdsRepository, ReportTreeRootHolder treeRootHolder,
-                                 DuplicationRepository duplicationRepository) {
+  public PersistDuplicationsStep(DbClient dbClient, DbIdsRepository dbIdsRepository, TreeRootHolder treeRootHolder,
+    DuplicationRepository duplicationRepository) {
     this.dbClient = dbClient;
     this.dbIdsRepository = dbIdsRepository;
     this.treeRootHolder = treeRootHolder;
@@ -68,7 +68,7 @@ public class PersistDuplicationsStep implements ComputationStep {
     try {
       MetricDto duplicationMetric = dbClient.metricDao().selectOrFailByKey(session, CoreMetrics.DUPLICATIONS_DATA_KEY);
       new DepthTraversalTypeAwareCrawler(new DuplicationVisitor(session, duplicationMetric))
-          .visit(treeRootHolder.getRoot());
+        .visit(treeRootHolder.getRoot());
       session.commit();
     } finally {
       MyBatis.closeQuietly(session);
@@ -97,10 +97,10 @@ public class PersistDuplicationsStep implements ComputationStep {
     private void saveDuplications(Component component, Iterable<Duplication> duplications) {
       String duplicationXml = createXmlDuplications(component.getKey(), duplications);
       MeasureDto measureDto = new MeasureDto()
-          .setMetricId(duplicationMetric.getId())
-          .setData(duplicationXml)
-          .setComponentId(dbIdsRepository.getComponentId(component))
-          .setSnapshotId(dbIdsRepository.getSnapshotId(component));
+        .setMetricId(duplicationMetric.getId())
+        .setData(duplicationXml)
+        .setComponentId(dbIdsRepository.getComponentId(component))
+        .setSnapshotId(dbIdsRepository.getSnapshotId(component));
       dbClient.measureDao().insert(session, measureDto);
     }
 
@@ -142,9 +142,9 @@ public class PersistDuplicationsStep implements ComputationStep {
     private void appendDuplication(StringBuilder xml, String componentKey, TextBlock textBlock) {
       int length = textBlock.getEnd() - textBlock.getStart() + 1;
       xml.append("<b s=\"").append(textBlock.getStart())
-          .append("\" l=\"").append(length)
-          .append("\" r=\"").append(StringEscapeUtils.escapeXml(componentKey))
-          .append("\"/>");
+        .append("\" l=\"").append(length)
+        .append("\" r=\"").append(StringEscapeUtils.escapeXml(componentKey))
+        .append("\"/>");
     }
   }
 
index a0b8974485db419e2cbdebeea9a9064fcf38c44a..cb96a8e02f1e0f6abad93a89b5c806205fcc0894 100644 (file)
@@ -36,11 +36,11 @@ import java.util.Set;
 import org.apache.ibatis.session.ResultContext;
 import org.apache.ibatis.session.ResultHandler;
 import org.sonar.api.utils.System2;
-import org.sonar.core.util.Uuids;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.util.CloseableIterator;
+import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.MyBatis;
@@ -52,7 +52,7 @@ import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.ComponentVisitor;
 import org.sonar.server.computation.component.CrawlerDepthLimit;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
-import org.sonar.server.computation.component.ReportTreeRootHolder;
+import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.computation.component.TypeAwareVisitorAdapter;
 
 public class PersistTestsStep implements ComputationStep {
@@ -62,9 +62,9 @@ public class PersistTestsStep implements ComputationStep {
   private final DbClient dbClient;
   private final System2 system;
   private final BatchReportReader reportReader;
-  private final ReportTreeRootHolder treeRootHolder;
+  private final TreeRootHolder treeRootHolder;
 
-  public PersistTestsStep(DbClient dbClient, System2 system, BatchReportReader reportReader, ReportTreeRootHolder treeRootHolder) {
+  public PersistTestsStep(DbClient dbClient, System2 system, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
     this.dbClient = dbClient;
     this.system = system;
     this.reportReader = reportReader;
index 92335b9abdefb49fbc3e70c6c742bb7fdcf149a1..865f914596638d3ca4c33f4b6956dac611b8903f 100644 (file)
  */
 package org.sonar.server.computation.batch;
 
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
+import org.junit.rules.ExternalResource;
 import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.CrawlerDepthLimit;
-import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
-import org.sonar.server.computation.component.MutableTreeRootHolder;
-import org.sonar.server.computation.component.ReportTreeRootHolder;
 import org.sonar.server.computation.component.TreeRootHolder;
-import org.sonar.server.computation.component.TypeAwareVisitorAdapter;
+import org.sonar.server.computation.component.TreeRootHolderImpl;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
-
-public class TreeRootHolderRule implements TestRule, MutableTreeRootHolder, ReportTreeRootHolder {
-  private Component root;
-  private Map<Integer, Component> componentsByRef = new HashMap<>();
+public class TreeRootHolderRule extends ExternalResource implements TreeRootHolder {
+  protected TreeRootHolderImpl delegate = new TreeRootHolderImpl();
 
   @Override
-  public Statement apply(final Statement statement, Description description) {
-    return new Statement() {
-      @Override
-      public void evaluate() throws Throwable {
-        try {
-          statement.evaluate();
-        } finally {
-          clear();
-        }
-      }
-    };
+  protected void after() {
+    this.delegate = null;
   }
 
-  private void clear() {
-    this.root = null;
-    this.componentsByRef.clear();
+  public TreeRootHolderRule setRoot(Component newRoot) {
+    delegate = new TreeRootHolderImpl();
+    delegate.setRoot(newRoot);
+    return this;
   }
 
   @Override
   public Component getRoot() {
-    checkInitialized();
-
-    return root;
+    return delegate.getRoot();
   }
 
   @Override
   public Component getComponentByRef(int ref) {
-    checkInitialized();
-
-    Component component = componentsByRef.get(ref);
-    checkArgument(component != null, "Component with ref '%s' hasn't been found", ref);
-    return component;
+    return delegate.getComponentByRef(ref);
   }
 
-  private void checkInitialized() {
-    checkState(root != null, "Root has not been set in %s", TreeRootHolder.class.getSimpleName());
+  @Override
+  public Component getComponentByKey(String key) {
+    return delegate.getComponentByKey(key);
   }
 
-  public TreeRootHolderRule setRoot(Component newRoot) {
-    this.root = requireNonNull(newRoot);
-    if (newRoot.getType().isReportType()) {
-      new DepthTraversalTypeAwareCrawler(new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, POST_ORDER) {
-        @Override
-        public void visitAny(Component component) {
-          componentsByRef.put(component.getReportAttributes().getRef(), component);
-        }
-      }).visit(root);
-    }
-    return this;
+  @Override
+  public boolean hasComponentWithKey(String key) {
+    return delegate.hasComponentWithKey(key);
   }
 }
index f2309b75722f81db6be1c4a925d67e2b7a864736..b9124c96c4768e8c9d0fe81e0f7a224181318f0b 100644 (file)
@@ -24,6 +24,7 @@ import org.sonar.server.computation.batch.TreeRootHolderRule;
 public class MutableTreeRootHolderRule extends TreeRootHolderRule implements MutableTreeRootHolder {
   @Override
   public MutableTreeRootHolderRule setRoot(Component newRoot) {
-    return (MutableTreeRootHolderRule)super.setRoot(newRoot);
+    delegate.setRoot(newRoot);
+    return this;
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/ReportTreeRootHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/ReportTreeRootHolderImplTest.java
deleted file mode 100644 (file)
index 62e17c7..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.computation.component;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ReportTreeRootHolderImplTest {
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  ReportTreeRootHolderImpl treeRootHolder = new ReportTreeRootHolderImpl();
-  Component project = ReportComponent.DUMB_PROJECT;
-
-  @Test
-  public void setRoot_throws_NPE_if_arg_is_null() {
-    thrown.expect(NullPointerException.class);
-    treeRootHolder.setRoot(null);
-  }
-
-  @Test
-  public void getRoot_throws_ISE_if_root_has_not_been_set_yet() {
-    thrown.expect(IllegalStateException.class);
-    treeRootHolder.getRoot();
-  }
-
-  @Test
-  public void verify_setRoot_getRoot() {
-    treeRootHolder.setRoot(project);
-    assertThat(treeRootHolder.getRoot()).isSameAs(project);
-  }
-
-  @Test
-  public void get_by_ref() {
-    Component file = ReportComponent.builder(Component.Type.FILE, 4).build();
-    Component directory = ReportComponent.builder(Component.Type.DIRECTORY, 3).addChildren(file).build();
-    Component module = ReportComponent.builder(Component.Type.MODULE, 2).addChildren(directory).build();
-    Component project = ReportComponent.builder(Component.Type.PROJECT, 1).addChildren(module).build();
-    treeRootHolder.setRoot(project);
-
-    assertThat(treeRootHolder.getComponentByRef(1)).isEqualTo(project);
-    assertThat(treeRootHolder.getComponentByRef(2)).isEqualTo(module);
-    assertThat(treeRootHolder.getComponentByRef(3)).isEqualTo(directory);
-    assertThat(treeRootHolder.getComponentByRef(4)).isEqualTo(file);
-  }
-
-  @Test
-  public void fail_to_get_by_ref_if_root_not_set() {
-    thrown.expect(IllegalStateException.class);
-    treeRootHolder.getComponentByRef(project.getReportAttributes().getRef());
-  }
-
-  @Test
-  public void fail_to_get_by_ref_if_ref_not_found() {
-    thrown.expect(IllegalArgumentException.class);
-    treeRootHolder.setRoot(project);
-    treeRootHolder.getComponentByRef(123);
-  }
-}
index 069d77ea7b7d2613c71718bd081c0ab7da475270..ecce5f0a22d57049e8e985af49014fec55711f28 100644 (file)
@@ -24,31 +24,182 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW;
+import static org.sonar.server.computation.component.Component.Type.VIEW;
+import static org.sonar.server.computation.component.ReportComponent.DUMB_PROJECT;
 
 public class TreeRootHolderImplTest {
 
+  private static final ReportComponent SOME_REPORT_COMPONENT_TREE = ReportComponent.builder(PROJECT, 1)
+    .addChildren(
+        ReportComponent.builder(MODULE, 2)
+            .addChildren(ReportComponent.builder(DIRECTORY, 3)
+                .addChildren(
+                    ReportComponent.builder(FILE, 4).build()
+                )
+                .build())
+            .build()
+    )
+    .build();
+  private static final ViewsComponent SOME_VIEWS_COMPONENT_TREE = ViewsComponent.builder(VIEW, 1)
+    .addChildren(
+        ViewsComponent.builder(VIEW, 2)
+            .addChildren(ViewsComponent.builder(PROJECT_VIEW, 3).build())
+            .build()
+    )
+    .build();
+
   @Rule
-  public ExpectedException thrown = ExpectedException.none();
+  public ExpectedException expectedException = ExpectedException.none();
 
-  TreeRootHolderImpl treeRootHolder = new TreeRootHolderImpl();
-  Component project = ReportComponent.DUMB_PROJECT;
+  private TreeRootHolderImpl underTest = new TreeRootHolderImpl();
 
   @Test
   public void setRoot_throws_NPE_if_arg_is_null() {
-    thrown.expect(NullPointerException.class);
-    treeRootHolder.setRoot(null);
+    expectedException.expect(NullPointerException.class);
+    expectedException.expectMessage("root can not be null");
+
+    underTest.setRoot(null);
+  }
+
+  @Test
+  public void setRoot_throws_ISE_when_called_twice() {
+    underTest.setRoot(DUMB_PROJECT);
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("root can not be set twice in holder");
+
+    underTest.setRoot(DUMB_PROJECT);
   }
 
   @Test
   public void getRoot_throws_ISE_if_root_has_not_been_set_yet() {
-    thrown.expect(IllegalStateException.class);
-    treeRootHolder.getRoot();
+    expectNotInitialized_ISE();
+
+    underTest.getRoot();
+  }
+
+  @Test
+  public void getComponentByRef_throws_ISE_if_root_has_not_been_set() {
+    expectNotInitialized_ISE();
+
+    underTest.getComponentByRef(12);
+  }
+
+  @Test
+  public void getComponentByRef_returns_any_report_component_in_the_tree() {
+    underTest.setRoot(SOME_REPORT_COMPONENT_TREE);
+
+    for (int i = 1; i <= 4; i++) {
+      assertThat(underTest.getComponentByRef(i).getReportAttributes().getRef()).isEqualTo(i);
+    }
+  }
+
+  @Test
+  public void getComponentByRef_throws_IAE_if_holder_does_not_contain_specified_component() {
+    underTest.setRoot(SOME_REPORT_COMPONENT_TREE);
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Component with ref '6' can't be found");
+
+    underTest.getComponentByRef(6);
+  }
+
+  @Test
+  public void getComponentByRef_throws_IAE_if_holder_contains_View_tree() {
+    underTest.setRoot(SOME_VIEWS_COMPONENT_TREE);
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Component with ref '1' can't be found");
+
+    underTest.getComponentByRef(1);
+  }
+
+  @Test
+  public void getComponentByKey_throws_NPE_if_key_is_null() {
+    expectedException.expect(NullPointerException.class);
+    expectedException.expectMessage("key can not be null");
+
+    underTest.getComponentByKey(null);
+  }
+
+  @Test
+  public void getComponentByKey_throws_ISE_if_root_has_not_been_set() {
+    expectNotInitialized_ISE();
+
+    underTest.getComponentByKey("key");
+  }
+
+  @Test
+  public void getComponentByKey_returns_any_report_component_in_the_tree() {
+    underTest.setRoot(SOME_REPORT_COMPONENT_TREE);
+
+    for (int i = 1; i <= 4; i++) {
+      String key = "key_" + i;
+      assertThat(underTest.getComponentByKey(key).getKey()).isEqualTo(key);
+    }
+  }
+
+  @Test
+  public void getComponentByKey_returns_any_views_component_in_the_tree() {
+    underTest.setRoot(SOME_VIEWS_COMPONENT_TREE);
+
+    for (int i = 1; i <= 3; i++) {
+      String key = String.valueOf(i);
+      assertThat(underTest.getComponentByKey(key).getKey()).isEqualTo(key);
+    }
   }
 
   @Test
   public void verify_setRoot_getRoot() {
-    treeRootHolder.setRoot(project);
-    assertThat(treeRootHolder.getRoot()).isSameAs(project);
+    underTest.setRoot(DUMB_PROJECT);
+    assertThat(underTest.getRoot()).isSameAs(DUMB_PROJECT);
+  }
+
+  @Test
+  public void hasComponentWithKey_throws_NPE_if_key_is_null() {
+    expectedException.expect(NullPointerException.class);
+    expectedException.expectMessage("key can not be null");
+
+    underTest.hasComponentWithKey(null);
+  }
+
+  @Test
+  public void hasComponentWithKey_throws_ISE_if_root_has_not_been_set() {
+    expectNotInitialized_ISE();
+
+    underTest.hasComponentWithKey("key");
+  }
+
+  @Test
+  public void hasComponentWithKey_returns_true_for_any_report_component_in_the_tree() {
+    underTest.setRoot(SOME_REPORT_COMPONENT_TREE);
+
+    for (int i = 1; i <= 4; i++) {
+      String key = "key_" + i;
+      assertThat(underTest.hasComponentWithKey(key)).isTrue();
+    }
+    assertThat(underTest.hasComponentWithKey("toto")).isFalse();
+  }
+
+  @Test
+  public void hasComponentWithKey_returns_true_for_any_views_component_in_the_tree() {
+    underTest.setRoot(SOME_VIEWS_COMPONENT_TREE);
+
+    for (int i = 1; i <= 3; i++) {
+      String key = String.valueOf(i);
+      assertThat(underTest.hasComponentWithKey(key)).isTrue();
+    }
+    assertThat(underTest.hasComponentWithKey("toto")).isFalse();
+  }
+
+  private void expectNotInitialized_ISE() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Holder has not been initialized yet");
   }
 
 }
index dd1950d026feb45ade80707657a5138bc9a775cb..9946698c56581282c9121186c8954f78660cca48 100644 (file)
@@ -25,7 +25,7 @@ import javax.annotation.CheckForNull;
 import org.junit.rules.ExternalResource;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.ReportTreeRootHolder;
+import org.sonar.server.computation.component.TreeRootHolder;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -34,7 +34,7 @@ import static java.util.Objects.requireNonNull;
 
 public class ComponentIssuesRepositoryRule extends ExternalResource implements MutableComponentIssuesRepository, ComponentIssuesRepository {
 
-  private final ReportTreeRootHolder reportTreeRootHolder;
+  private final TreeRootHolder treeRootHolder;
 
   @CheckForNull
   private List<DefaultIssue> issues;
@@ -42,8 +42,8 @@ public class ComponentIssuesRepositoryRule extends ExternalResource implements M
   @CheckForNull
   private Component component;
 
-  public ComponentIssuesRepositoryRule(ReportTreeRootHolder reportTreeRootHolder) {
-    this.reportTreeRootHolder = reportTreeRootHolder;
+  public ComponentIssuesRepositoryRule(TreeRootHolder treeRootHolder) {
+    this.treeRootHolder = treeRootHolder;
   }
 
   @Override
@@ -54,7 +54,7 @@ public class ComponentIssuesRepositoryRule extends ExternalResource implements M
 
   public void setIssues(int componentRef, List<DefaultIssue> issues) {
     this.issues = requireNonNull(issues, "issues cannot be null");
-    Component component = reportTreeRootHolder.getComponentByRef(componentRef);
+    Component component = treeRootHolder.getComponentByRef(componentRef);
     checkArgument(component != null, String.format("Component '%s' does not exists in the report ", componentRef));
     this.component = component;
   }
@@ -67,7 +67,7 @@ public class ComponentIssuesRepositoryRule extends ExternalResource implements M
 
   public List<DefaultIssue> getIssues(int componentRef) {
     checkState(this.component != null && this.issues != null, "Issues have not been initialized");
-    Component component = reportTreeRootHolder.getComponentByRef(componentRef);
+    Component component = treeRootHolder.getComponentByRef(componentRef);
     checkArgument(component != null, String.format("Component '%s' does not exists in the report ", componentRef));
     checkArgument(component == this.component,
       String.format("Only issues from component '%s' are available, but wanted component is '%s'.",
index 0da0ba15dd452e94335c1058be74271931c6c66b..a57e5807d2463c4869b99275f42ab7065a7365b5 100644 (file)
@@ -136,7 +136,7 @@ public class LoadDuplicationsFromReportStepTest {
     reportReader.putDuplications(FILE_1_REF, createDuplication(singleLineTextRange(line), createInProjectDuplicate(666, line + 1)));
 
     expectedException.expect(IllegalArgumentException.class);
-    expectedException.expectMessage("Component with ref '666' hasn't been found");
+    expectedException.expectMessage("Component with ref '666' can't be found");
 
     underTest.execute();
   }