]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6589 remove ComputationContainer (and use only CEContainer)
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 26 May 2015 15:01:40 +0000 (17:01 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 1 Jun 2015 15:08:28 +0000 (17:08 +0200)
25 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ComputationService.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThread.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThreadLauncher.java
server/sonar-server/src/main/java/org/sonar/server/computation/activity/ActivityManager.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/activity/CEActivityManager.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/batch/CEBatchReportReader.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/container/CEContainer.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainer.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactory.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactoryImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
server/sonar-server/src/test/java/org/sonar/server/computation/ComputationContainerTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ComputationServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadLauncherTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/activity/ActivityManagerTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/activity/CEActivityManagerTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/container/ComputeEngineContainerImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ComputationStepsTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/activity/ActivityManagerTest/shared.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/activity/CEActivityManagerTest/shared.xml [deleted file]
sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java
deleted file mode 100644 (file)
index e805887..0000000
+++ /dev/null
@@ -1,97 +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;
-
-import java.util.Arrays;
-import java.util.List;
-import org.sonar.core.issue.db.UpdateConflictResolver;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.activity.CEActivityManager;
-import org.sonar.server.computation.batch.CEBatchReportReader;
-import org.sonar.server.computation.batch.ReportExtractor;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.ProjectSettingsRepository;
-import org.sonar.server.computation.container.CEContainer;
-import org.sonar.server.computation.issue.IssueCache;
-import org.sonar.server.computation.issue.IssueComputation;
-import org.sonar.server.computation.issue.RuleCache;
-import org.sonar.server.computation.issue.RuleCacheLoader;
-import org.sonar.server.computation.issue.ScmAccountCache;
-import org.sonar.server.computation.issue.ScmAccountCacheLoader;
-import org.sonar.server.computation.issue.SourceLinesCache;
-import org.sonar.server.computation.language.PlatformLanguageRepository;
-import org.sonar.server.computation.measure.MetricCache;
-import org.sonar.server.computation.step.ComputationSteps;
-import org.sonar.server.platform.Platform;
-import org.sonar.server.view.index.ViewIndex;
-
-public class ComputationContainer {
-
-  /**
-   * List of all objects to be injected in the picocontainer dedicated to computation stack.
-   * Does not contain the steps declared in {@link org.sonar.server.computation.step.ComputationSteps#orderedStepClasses()}.
-   */
-  static List componentClasses() {
-    return Arrays.asList(
-      CEActivityManager.class,
-      ReportExtractor.class,
-      CEBatchReportReader.class,
-
-      // repositories
-      PlatformLanguageRepository.class,
-      ProjectSettingsRepository.class,
-
-      // component caches
-      DbComponentsRefCache.class,
-
-      // issues
-      ScmAccountCacheLoader.class,
-      ScmAccountCache.class,
-      SourceLinesCache.class,
-      IssueComputation.class,
-      RuleCache.class,
-      RuleCacheLoader.class,
-      IssueCache.class,
-      MetricCache.class,
-      UpdateConflictResolver.class,
-
-      // views
-      ViewIndex.class);
-  }
-
-  public void execute(ReportQueue.Item item) {
-    ComponentContainer container = Platform.getInstance().getContainer();
-
-    ComponentContainer ceContainer = new CEContainer(container);
-    ceContainer.add(ceContainer);
-    ceContainer.add(item);
-    ceContainer.addSingletons(componentClasses());
-    ceContainer.addSingletons(ComputationSteps.orderedStepClasses());
-    try {
-      ceContainer.getComponentByType(ComputationService.class).process();
-    } finally {
-      ceContainer.stopComponents();
-      // TODO not possible to have multiple children -> will be
-      // a problem when we will have multiple concurrent computation workers
-      container.removeChild();
-    }
-  }
-
-}
index 5646d2f6efb8f7d5826ae5af448ba397edc9c588..a984fe2c1bdd5cb467ebcc425d5ebb45983c5ba3 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.server.computation.activity.CEActivityManager;
+import org.sonar.server.computation.activity.ActivityManager;
 import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.ComponentTreeBuilders;
 import org.sonar.server.computation.language.LanguageRepository;
@@ -44,12 +44,12 @@ public class ComputationService {
   private final ReportQueue.Item item;
   private final ComputationSteps steps;
   private final BatchReportReader reportReader;
-  private final CEActivityManager activityManager;
+  private final ActivityManager activityManager;
   private final System2 system;
   private final DbClient dbClient;
   private final LanguageRepository languageRepository;
 
-  public ComputationService(ReportQueue.Item item, ComputationSteps steps, CEActivityManager activityManager, System2 system,
+  public ComputationService(ReportQueue.Item item, ComputationSteps steps, ActivityManager activityManager, System2 system,
     BatchReportReader reportReader, DbClient dbClient, LanguageRepository languageRepository) {
     this.item = item;
     this.steps = steps;
index d60cc0b7f62c305b6898ee8c83d100aa73be8aaa..aa621b317e87c1e70bd2f8135845b0a59672b456 100644 (file)
 
 package org.sonar.server.computation;
 
-import com.google.common.annotations.VisibleForTesting;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.container.ComputeEngineContainer;
+import org.sonar.server.computation.container.ContainerFactory;
 
 /**
  * This thread pops a report from the queue and integrate it.
@@ -32,17 +34,13 @@ public class ComputationThread implements Runnable {
   private static final Logger LOG = Loggers.get(ComputationThread.class);
 
   private final ReportQueue queue;
-  private final ComputationContainer container;
+  private final ComponentContainer sqContainer;
+  private final ContainerFactory containerFactory;
 
-  public ComputationThread(ReportQueue queue) {
+  public ComputationThread(ReportQueue queue, ComponentContainer sqContainer, ContainerFactory containerFactory) {
     this.queue = queue;
-    this.container = new ComputationContainer();
-  }
-
-  @VisibleForTesting
-  ComputationThread(ReportQueue queue, ComputationContainer container) {
-    this.queue = queue;
-    this.container = container;
+    this.sqContainer = sqContainer;
+    this.containerFactory = containerFactory;
   }
 
   @Override
@@ -53,15 +51,20 @@ public class ComputationThread implements Runnable {
     } catch (Exception e) {
       LOG.error("Failed to pop the queue of analysis reports", e);
     }
-    if (item != null) {
-      try {
-        container.execute(item);
-      } catch (Throwable e) {
-        LOG.error(String.format(
-          "Failed to process analysis report %d of project %s", item.dto.getId(), item.dto.getProjectKey()), e);
-      } finally {
-        removeSilentlyFromQueue(item);
-      }
+    if (item == null) {
+      return;
+    }
+
+    ComputeEngineContainer computeEngineContainer = containerFactory.create(sqContainer, item);
+    try {
+      computeEngineContainer.process();
+    } catch (Throwable e) {
+      LOG.error(String.format(
+        "Failed to process analysis report %d of project %s", item.dto.getId(), item.dto.getProjectKey()), e);
+    } finally {
+      computeEngineContainer.cleanup();
+
+      removeSilentlyFromQueue(item);
     }
   }
 
index c91d3c88fef2fa942f2bf6c165851d7ed9f3a8ba..01f43c73ef3436b591da9c2b64bd1ab0bf8e77fb 100644 (file)
@@ -22,29 +22,35 @@ package org.sonar.server.computation;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import org.picocontainer.Startable;
-import org.sonar.api.platform.Server;
-import org.sonar.api.platform.ServerStartHandler;
-
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
+import org.picocontainer.Startable;
+import org.sonar.api.platform.Server;
+import org.sonar.api.platform.ServerStartHandler;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.container.ContainerFactory;
+import org.sonar.server.computation.container.ContainerFactoryImpl;
 
 public class ComputationThreadLauncher implements Startable, ServerStartHandler {
 
   public static final String THREAD_NAME_PREFIX = "computation-";
 
   private final ReportQueue queue;
+  private final ComponentContainer sqContainer;
   private final ScheduledExecutorService executorService;
+  private final ContainerFactory containerFactory;
 
   private final long delayBetweenTasks;
   private final long delayForFirstStart;
   private final TimeUnit timeUnit;
 
-  public ComputationThreadLauncher(ReportQueue queue) {
+  public ComputationThreadLauncher(ReportQueue queue, ComponentContainer sqContainer) {
     this.queue = queue;
+    this.sqContainer = sqContainer;
     this.executorService = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
+    this.containerFactory = new ContainerFactoryImpl();
 
     this.delayBetweenTasks = 10;
     this.delayForFirstStart = 0;
@@ -52,8 +58,11 @@ public class ComputationThreadLauncher implements Startable, ServerStartHandler
   }
 
   @VisibleForTesting
-  ComputationThreadLauncher(ReportQueue queue, long delayForFirstStart, long delayBetweenTasks, TimeUnit timeUnit) {
+  ComputationThreadLauncher(ReportQueue queue, ComponentContainer sqContainer, ContainerFactory containerFactory,
+    long delayForFirstStart, long delayBetweenTasks, TimeUnit timeUnit) {
     this.queue = queue;
+    this.sqContainer = sqContainer;
+    this.containerFactory = containerFactory;
     this.executorService = Executors.newSingleThreadScheduledExecutor(newThreadFactory());
 
     this.delayBetweenTasks = delayBetweenTasks;
@@ -72,12 +81,12 @@ public class ComputationThreadLauncher implements Startable, ServerStartHandler
   }
 
   public void startAnalysisTaskNow() {
-    executorService.execute(new ComputationThread(queue));
+    executorService.execute(new ComputationThread(queue, sqContainer, containerFactory));
   }
 
   @Override
   public void onServerStart(Server server) {
-    executorService.scheduleAtFixedRate(new ComputationThread(queue), delayForFirstStart, delayBetweenTasks, timeUnit);
+    executorService.scheduleAtFixedRate(new ComputationThread(queue, sqContainer, containerFactory), delayForFirstStart, delayBetweenTasks, timeUnit);
   }
 
   private ThreadFactory newThreadFactory() {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/activity/ActivityManager.java b/server/sonar-server/src/main/java/org/sonar/server/computation/activity/ActivityManager.java
new file mode 100644 (file)
index 0000000..d3aa9de
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.activity;
+
+import javax.annotation.CheckForNull;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.activity.Activity;
+import org.sonar.server.activity.ActivityService;
+import org.sonar.server.db.DbClient;
+
+import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
+public class ActivityManager {
+  private final ActivityService activityService;
+  private final DbClient dbClient;
+
+  public ActivityManager(ActivityService activityService, DbClient dbClient) {
+    this.activityService = activityService;
+    this.dbClient = dbClient;
+  }
+
+  public void saveActivity(AnalysisReportDto report) {
+    ComponentDto project = loadProject(report.getProjectKey());
+    Activity activity = new Activity();
+    activity.setType(Activity.Type.ANALYSIS_REPORT);
+    activity.setAction("LOG_ANALYSIS_REPORT");
+    activity
+        .setData("key", String.valueOf(report.getId()))
+        .setData("projectKey", report.getProjectKey())
+        .setData("status", String.valueOf(report.getStatus()))
+        .setData("submittedAt", formatDateTimeNullSafe(longToDate(report.getCreatedAt())))
+        .setData("startedAt", formatDateTimeNullSafe(longToDate(report.getStartedAt())))
+        .setData("finishedAt", formatDateTimeNullSafe(longToDate(report.getFinishedAt())));
+    if (project != null) {
+      activity
+          .setData("projectName", project.name())
+          .setData("projectUuid", project.uuid());
+    }
+    activityService.save(activity);
+  }
+
+  @CheckForNull
+  private ComponentDto loadProject(String projectKey) {
+    DbSession session = dbClient.openSession(false);
+    try {
+      return dbClient.componentDao().selectNullableByKey(session, projectKey);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/activity/CEActivityManager.java b/server/sonar-server/src/main/java/org/sonar/server/computation/activity/CEActivityManager.java
deleted file mode 100644 (file)
index c77700a..0000000
+++ /dev/null
@@ -1,72 +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.activity;
-
-import javax.annotation.CheckForNull;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.server.activity.Activity;
-import org.sonar.server.activity.ActivityService;
-import org.sonar.server.db.DbClient;
-
-import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe;
-import static org.sonar.api.utils.DateUtils.longToDate;
-
-public class CEActivityManager {
-  private final ActivityService activityService;
-  private final DbClient dbClient;
-
-  public CEActivityManager(ActivityService activityService, DbClient dbClient) {
-    this.activityService = activityService;
-    this.dbClient = dbClient;
-  }
-
-  public void saveActivity(AnalysisReportDto report) {
-    ComponentDto project = loadProject(report.getProjectKey());
-    Activity activity = new Activity();
-    activity.setType(Activity.Type.ANALYSIS_REPORT);
-    activity.setAction("LOG_ANALYSIS_REPORT");
-    activity
-        .setData("key", String.valueOf(report.getId()))
-        .setData("projectKey", report.getProjectKey())
-        .setData("status", String.valueOf(report.getStatus()))
-        .setData("submittedAt", formatDateTimeNullSafe(longToDate(report.getCreatedAt())))
-        .setData("startedAt", formatDateTimeNullSafe(longToDate(report.getStartedAt())))
-        .setData("finishedAt", formatDateTimeNullSafe(longToDate(report.getFinishedAt())));
-    if (project != null) {
-      activity
-          .setData("projectName", project.name())
-          .setData("projectUuid", project.uuid());
-    }
-    activityService.save(activity);
-  }
-
-  @CheckForNull
-  private ComponentDto loadProject(String projectKey) {
-    DbSession session = dbClient.openSession(false);
-    try {
-      return dbClient.componentDao().selectNullableByKey(session, projectKey);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java
new file mode 100644 (file)
index 0000000..7799436
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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.batch;
+
+import com.google.common.base.Throwables;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Parser;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.NoSuchElementException;
+import javax.annotation.CheckForNull;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.LineIterator;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.util.CloseableIterator;
+
+public class BatchReportReaderImpl implements BatchReportReader {
+  private final org.sonar.batch.protocol.output.BatchReportReader delegate;
+
+  public BatchReportReaderImpl(ReportExtractor reportExtractor, ReportQueue.Item item) {
+    this.delegate = new org.sonar.batch.protocol.output.BatchReportReader(reportExtractor.extractReportInDir(item));
+  }
+
+  @Override
+  public BatchReport.Metadata readMetadata() {
+    return delegate.readMetadata();
+  }
+
+  @Override
+  public List<BatchReport.Measure> readComponentMeasures(int componentRef) {
+    return delegate.readComponentMeasures(componentRef);
+  }
+
+  @Override
+  @CheckForNull
+  public BatchReport.Changesets readChangesets(int componentRef) {
+    return delegate.readChangesets(componentRef);
+  }
+
+  @Override
+  public BatchReport.Component readComponent(int componentRef) {
+    return delegate.readComponent(componentRef);
+  }
+
+  @Override
+  public List<BatchReport.Issue> readComponentIssues(int componentRef) {
+    return delegate.readComponentIssues(componentRef);
+  }
+
+  @Override
+  public BatchReport.Issues readDeletedComponentIssues(int deletedComponentRef) {
+    return delegate.readDeletedComponentIssues(deletedComponentRef);
+  }
+
+  @Override
+  public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
+    return delegate.readComponentDuplications(componentRef);
+  }
+
+  @Override
+  public List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef) {
+    return delegate.readComponentSymbols(componentRef);
+  }
+
+  @Override
+  @CheckForNull
+  public CloseableIterator<BatchReport.SyntaxHighlighting> readComponentSyntaxHighlighting(int fileRef) {
+    File file = delegate.readComponentSyntaxHighlighting(fileRef);
+    if (file == null) {
+      return CloseableIterator.emptyCloseableIterator();
+    }
+
+    try {
+      return new ParserCloseableIterator<>(BatchReport.SyntaxHighlighting.PARSER, FileUtils.openInputStream(file));
+    } catch (IOException e) {
+      Throwables.propagate(e);
+      // actually never reached
+      return CloseableIterator.emptyCloseableIterator();
+    }
+  }
+
+  @Override
+  public CloseableIterator<BatchReport.Coverage> readComponentCoverage(int fileRef) {
+    File file = delegate.readComponentCoverage(fileRef);
+    if (file == null) {
+      return CloseableIterator.emptyCloseableIterator();
+    }
+
+    try {
+      return new ParserCloseableIterator<>(BatchReport.Coverage.PARSER, FileUtils.openInputStream(file));
+    } catch (IOException e) {
+      Throwables.propagate(e);
+      // actually never reached
+      return CloseableIterator.emptyCloseableIterator();
+    }
+  }
+
+  @Override
+  public CloseableIterator<String> readFileSource(int fileRef) {
+    File file = delegate.readFileSource(fileRef);
+    if (file == null) {
+      throw new IllegalStateException("Unable to find source for file #" + fileRef + ". File does not exist: " + file);
+    }
+
+    try {
+      final LineIterator lineIterator = IOUtils.lineIterator(FileUtils.openInputStream(file), StandardCharsets.UTF_8);
+      return new CloseableIterator<String>() {
+        @Override
+        public boolean hasNext() {
+          return lineIterator.hasNext();
+        }
+
+        @Override
+        public String next() {
+          return lineIterator.next();
+        }
+
+        @Override
+        protected String doNext() {
+          // never called anyway
+          throw new NoSuchElementException("Empty closeable Iterator has no element");
+        }
+
+        @Override
+        protected void doClose() throws Exception {
+          lineIterator.close();
+        }
+      };
+    } catch (IOException e) {
+      throw new IllegalStateException("Fail to traverse file: " + file, e);
+    }
+  }
+
+  @Override
+  public CloseableIterator<BatchReport.Test> readTests(int testFileRef) {
+    File file = delegate.readTests(testFileRef);
+    if (file == null) {
+      return CloseableIterator.emptyCloseableIterator();
+    }
+
+    try {
+      return new ParserCloseableIterator<>(BatchReport.Test.PARSER, FileUtils.openInputStream(file));
+    } catch (IOException e) {
+      Throwables.propagate(e);
+      // actually never reached
+      return CloseableIterator.emptyCloseableIterator();
+    }
+  }
+
+  @Override
+  public CloseableIterator<BatchReport.CoverageDetail> readCoverageDetails(int testFileRef) {
+    File file = delegate.readCoverageDetails(testFileRef);
+    if (file == null) {
+      return CloseableIterator.emptyCloseableIterator();
+    }
+
+    try {
+      return new ParserCloseableIterator<>(BatchReport.CoverageDetail.PARSER, FileUtils.openInputStream(file));
+    } catch (IOException e) {
+      Throwables.propagate(e);
+      // actually never reached
+      return CloseableIterator.emptyCloseableIterator();
+    }
+  }
+
+  private static class ParserCloseableIterator<T> extends CloseableIterator<T> {
+    private final Parser<T> parser;
+    private final FileInputStream fileInputStream;
+
+    public ParserCloseableIterator(Parser<T> parser, FileInputStream fileInputStream) {
+      this.parser = parser;
+      this.fileInputStream = fileInputStream;
+    }
+
+    @Override
+    protected T doNext() {
+      try {
+        return parser.parseDelimitedFrom(fileInputStream);
+      } catch (InvalidProtocolBufferException e) {
+        Throwables.propagate(e);
+        // actually never reached
+        return null;
+      }
+    }
+
+    @Override
+    protected void doClose() throws Exception {
+      fileInputStream.close();
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/CEBatchReportReader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/CEBatchReportReader.java
deleted file mode 100644 (file)
index 810443e..0000000
+++ /dev/null
@@ -1,206 +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.batch;
-
-import com.google.common.base.Throwables;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.Parser;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.LineIterator;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.util.CloseableIterator;
-
-public class CEBatchReportReader implements BatchReportReader {
-  private final org.sonar.batch.protocol.output.BatchReportReader delegate;
-
-  public CEBatchReportReader(ReportExtractor reportExtractor, ReportQueue.Item item) {
-    this.delegate = new org.sonar.batch.protocol.output.BatchReportReader(reportExtractor.extractReportInDir(item));
-  }
-
-  @Override
-  public BatchReport.Metadata readMetadata() {
-    return delegate.readMetadata();
-  }
-
-  @Override
-  public List<BatchReport.Measure> readComponentMeasures(int componentRef) {
-    return delegate.readComponentMeasures(componentRef);
-  }
-
-  @Override
-  @CheckForNull
-  public BatchReport.Changesets readChangesets(int componentRef) {
-    return delegate.readChangesets(componentRef);
-  }
-
-  @Override
-  public BatchReport.Component readComponent(int componentRef) {
-    return delegate.readComponent(componentRef);
-  }
-
-  @Override
-  public List<BatchReport.Issue> readComponentIssues(int componentRef) {
-    return delegate.readComponentIssues(componentRef);
-  }
-
-  @Override
-  public BatchReport.Issues readDeletedComponentIssues(int deletedComponentRef) {
-    return delegate.readDeletedComponentIssues(deletedComponentRef);
-  }
-
-  @Override
-  public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
-    return delegate.readComponentDuplications(componentRef);
-  }
-
-  @Override
-  public List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef) {
-    return delegate.readComponentSymbols(componentRef);
-  }
-
-  @Override
-  @CheckForNull
-  public CloseableIterator<BatchReport.SyntaxHighlighting> readComponentSyntaxHighlighting(int fileRef) {
-    File file = delegate.readComponentSyntaxHighlighting(fileRef);
-    if (file == null) {
-      return CloseableIterator.emptyCloseableIterator();
-    }
-
-    try {
-      return new ParserCloseableIterator<>(BatchReport.SyntaxHighlighting.PARSER, FileUtils.openInputStream(file));
-    } catch (IOException e) {
-      Throwables.propagate(e);
-      // actually never reached
-      return CloseableIterator.emptyCloseableIterator();
-    }
-  }
-
-  @Override
-  public CloseableIterator<BatchReport.Coverage> readComponentCoverage(int fileRef) {
-    File file = delegate.readComponentCoverage(fileRef);
-    if (file == null) {
-      return CloseableIterator.emptyCloseableIterator();
-    }
-
-    try {
-      return new ParserCloseableIterator<>(BatchReport.Coverage.PARSER, FileUtils.openInputStream(file));
-    } catch (IOException e) {
-      Throwables.propagate(e);
-      // actually never reached
-      return CloseableIterator.emptyCloseableIterator();
-    }
-  }
-
-  @Override
-  public CloseableIterator<String> readFileSource(int fileRef) {
-    File file = delegate.readFileSource(fileRef);
-    if (file == null) {
-      throw new IllegalStateException("Unable to find source for file #" + fileRef + ". File does not exist: " + file);
-    }
-
-    try {
-      final LineIterator lineIterator = IOUtils.lineIterator(FileUtils.openInputStream(file), StandardCharsets.UTF_8);
-      return new CloseableIterator<String>() {
-        @Override
-        public boolean hasNext() {
-          return lineIterator.hasNext();
-        }
-
-        @Override
-        protected String doNext() {
-          return lineIterator.next();
-        }
-
-        @Override
-        protected void doClose() throws Exception {
-          lineIterator.close();
-        }
-      };
-    } catch (IOException e) {
-      throw new IllegalStateException("Fail to traverse file: " + file, e);
-    }
-  }
-
-  @Override
-  public CloseableIterator<BatchReport.Test> readTests(int testFileRef) {
-    File file = delegate.readTests(testFileRef);
-    if (file == null) {
-      return CloseableIterator.emptyCloseableIterator();
-    }
-
-    try {
-      return new ParserCloseableIterator<>(BatchReport.Test.PARSER, FileUtils.openInputStream(file));
-    } catch (IOException e) {
-      Throwables.propagate(e);
-      // actually never reached
-      return CloseableIterator.emptyCloseableIterator();
-    }
-  }
-
-  @Override
-  public CloseableIterator<BatchReport.CoverageDetail> readCoverageDetails(int testFileRef) {
-    File file = delegate.readCoverageDetails(testFileRef);
-    if (file == null) {
-      return CloseableIterator.emptyCloseableIterator();
-    }
-
-    try {
-      return new ParserCloseableIterator<>(BatchReport.CoverageDetail.PARSER, FileUtils.openInputStream(file));
-    } catch (IOException e) {
-      Throwables.propagate(e);
-      // actually never reached
-      return CloseableIterator.emptyCloseableIterator();
-    }
-  }
-
-  private static class ParserCloseableIterator<T> extends CloseableIterator<T> {
-    private final Parser<T> parser;
-    private final FileInputStream fileInputStream;
-
-    public ParserCloseableIterator(Parser<T> parser, FileInputStream fileInputStream) {
-      this.parser = parser;
-      this.fileInputStream = fileInputStream;
-    }
-
-    @Override
-    protected T doNext() {
-      try {
-        return parser.parseDelimitedFrom(fileInputStream);
-      } catch (InvalidProtocolBufferException e) {
-        Throwables.propagate(e);
-        // actually never reached
-        return null;
-      }
-    }
-
-    @Override
-    protected void doClose() throws Exception {
-      fileInputStream.close();
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/CEContainer.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/CEContainer.java
deleted file mode 100644 (file)
index 770376b..0000000
+++ /dev/null
@@ -1,55 +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.container;
-
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.DefaultPicoContainer;
-import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.behaviors.OptInCaching;
-import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
-import org.picocontainer.monitors.NullComponentMonitor;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.platform.ComponentContainer;
-
-public class CEContainer extends ComponentContainer {
-  public CEContainer(ComponentContainer parent) {
-    super(createContainer(parent), parent);
-  }
-
-  private static MutablePicoContainer createContainer(ComponentContainer parent) {
-    ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "close") {
-      @Override
-      public boolean isLazy(ComponentAdapter<?> adapter) {
-        return true;
-      }
-
-      @Override
-      public void start(Object component) {
-        Profiler profiler = Profiler.createIfTrace(Loggers.get(ComponentContainer.class));
-        profiler.start();
-        super.start(component);
-        profiler.stopTrace(component.getClass().getCanonicalName() + " started");
-      }
-    };
-
-    return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, parent.getPicoContainer());
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainer.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainer.java
new file mode 100644 (file)
index 0000000..6a0aa73
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.container;
+
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.ReportQueue.Item;
+import org.sonar.server.computation.step.ComputationStep;
+
+/**
+ * The Compute Engine container. Created for a specific parent {@link ComponentContainer} and a specific {@link Item}.
+ */
+public interface ComputeEngineContainer {
+  Item getItem();
+
+  ComponentContainer getParent();
+
+  /**
+   * Process the current {@link Item}
+   */
+  void process();
+
+  /**
+   * Clean's up resources after process has been called and has returned.
+   */
+  void cleanup();
+
+  /**
+   */
+  <T extends ComputationStep> T getStep(Class<T> type);
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
new file mode 100644 (file)
index 0000000..3d35d9e
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.container;
+
+import java.util.Arrays;
+import java.util.List;
+import org.picocontainer.ComponentAdapter;
+import org.picocontainer.DefaultPicoContainer;
+import org.picocontainer.MutablePicoContainer;
+import org.picocontainer.behaviors.OptInCaching;
+import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
+import org.picocontainer.monitors.NullComponentMonitor;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonar.core.issue.db.UpdateConflictResolver;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.ComputationService;
+import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.activity.ActivityManager;
+import org.sonar.server.computation.batch.BatchReportReaderImpl;
+import org.sonar.server.computation.batch.ReportExtractor;
+import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.ProjectSettingsRepository;
+import org.sonar.server.computation.issue.IssueCache;
+import org.sonar.server.computation.issue.IssueComputation;
+import org.sonar.server.computation.issue.RuleCache;
+import org.sonar.server.computation.issue.RuleCacheLoader;
+import org.sonar.server.computation.issue.ScmAccountCache;
+import org.sonar.server.computation.issue.ScmAccountCacheLoader;
+import org.sonar.server.computation.issue.SourceLinesCache;
+import org.sonar.server.computation.language.PlatformLanguageRepository;
+import org.sonar.server.computation.measure.MetricCache;
+import org.sonar.server.computation.step.ComputationStep;
+import org.sonar.server.computation.step.ComputationSteps;
+import org.sonar.server.view.index.ViewIndex;
+
+import static java.util.Objects.requireNonNull;
+
+public class ComputeEngineContainerImpl extends ComponentContainer implements ComputeEngineContainer {
+  private final ReportQueue.Item item;
+  private final ComputationSteps steps;
+
+  public ComputeEngineContainerImpl(ComponentContainer parent, ReportQueue.Item item) {
+    super(createContainer(requireNonNull(parent)));
+
+    this.item = item;
+    this.steps = new ComputationSteps(this);
+
+    populateContainer(requireNonNull(item));
+  }
+
+  @Override
+  public ReportQueue.Item getItem() {
+    return item;
+  }
+
+  private void populateContainer(ReportQueue.Item item) {
+    add(item);
+    add(steps);
+    addSingletons(componentClasses());
+    addSingletons(steps.orderedStepClasses());
+  }
+
+  /**
+   * Creates a PicContainer which extends the specified ComponentContainer <strong>but is not referenced in return</strong>
+   * and lazily starts its components.
+   */
+  private static MutablePicoContainer createContainer(ComponentContainer parent) {
+    ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "close") {
+      @Override
+      public boolean isLazy(ComponentAdapter<?> adapter) {
+        return true;
+      }
+
+      @Override
+      public void start(Object component) {
+        Profiler profiler = Profiler.createIfTrace(Loggers.get(ComponentContainer.class));
+        profiler.start();
+        super.start(component);
+        profiler.stopTrace(component.getClass().getCanonicalName() + " started");
+      }
+    };
+
+    return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, parent.getPicoContainer());
+  }
+
+  /**
+   * List of all objects to be injected in the picocontainer dedicated to computation stack.
+   * Does not contain the steps declared in {@link org.sonar.server.computation.step.ComputationSteps#orderedStepClasses()}.
+   */
+  private static List componentClasses() {
+    return Arrays.asList(
+      ActivityManager.class,
+      ReportExtractor.class,
+      BatchReportReaderImpl.class,
+
+      // repositories
+      PlatformLanguageRepository.class,
+      ProjectSettingsRepository.class,
+
+      // component caches
+      DbComponentsRefCache.class,
+
+      // issues
+      ScmAccountCacheLoader.class,
+      ScmAccountCache.class,
+      SourceLinesCache.class,
+      IssueComputation.class,
+      RuleCache.class,
+      RuleCacheLoader.class,
+      IssueCache.class,
+      MetricCache.class,
+      UpdateConflictResolver.class,
+
+      // views
+      ViewIndex.class,
+
+      // ComputationService
+      ComputationService.class
+      );
+  }
+
+  public void process() {
+    // calls the first
+    getComponentByType(ComputationService.class).process();
+  }
+
+  public void cleanup() {
+    stopComponents();
+  }
+
+  @Override
+  public <T extends ComputationStep> T getStep(Class<T> type) {
+    return getComponentByType(type);
+  }
+
+  @Override
+  public String toString() {
+    return "ComputeEngineContainerImpl";
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactory.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactory.java
new file mode 100644 (file)
index 0000000..7787a6c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.container;
+
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.ReportQueue;
+
+/**
+ * Compute
+ */
+public interface ContainerFactory {
+
+  ComputeEngineContainer create(ComponentContainer parent, ReportQueue.Item item);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactoryImpl.java
new file mode 100644 (file)
index 0000000..ce615c3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.container;
+
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.ReportQueue;
+
+public class ContainerFactoryImpl implements ContainerFactory {
+  @Override
+  public ComputeEngineContainer create(ComponentContainer parent, ReportQueue.Item item) {
+    return new ComputeEngineContainerImpl(parent, item);
+  }
+}
index 7360cd2b20cf474cda254f8fa3ff5f23723d3427..831299548c62797c3f9a679ab10cc0b1984e1ba7 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
 import java.util.Arrays;
 import java.util.List;
-import org.sonar.server.computation.container.CEContainer;
+import org.sonar.server.computation.container.ComputeEngineContainer;
 
 /**
  * Ordered list of steps to be executed
@@ -34,7 +34,7 @@ public class ComputationSteps {
    * List of all {@link org.sonar.server.computation.step.ComputationStep},
    * ordered by execution sequence.
    */
-  public static List<Class<? extends ComputationStep>> orderedStepClasses() {
+  public List<Class<? extends ComputationStep>> orderedStepClasses() {
     return Arrays.asList(
       PopulateComponentsUuidAndKeyStep.class,
       ValidateProjectStep.class,
@@ -71,17 +71,17 @@ public class ComputationSteps {
       SendIssueNotificationsStep.class);
   }
 
-  private final CEContainer ceContainer;
+  private final ComputeEngineContainer computeEngineContainer;
 
-  public ComputationSteps(CEContainer ceContainer) {
-    this.ceContainer = ceContainer;
+  public ComputationSteps(ComputeEngineContainer computeEngineContainer) {
+    this.computeEngineContainer = computeEngineContainer;
   }
 
   public Iterable<ComputationStep> instances() {
     return Iterables.transform(orderedStepClasses(), new Function<Class<? extends ComputationStep>, ComputationStep>() {
       @Override
       public ComputationStep apply(Class<? extends ComputationStep> input) {
-        ComputationStep computationStepType = ceContainer.getComponentByType(input);
+        ComputationStep computationStepType = computeEngineContainer.getStep(input);
         if (computationStepType == null) {
           throw new IllegalStateException(String.format("Component not found: %s", input));
         }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationContainerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationContainerTest.java
deleted file mode 100644 (file)
index 43b640d..0000000
+++ /dev/null
@@ -1,32 +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;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ComputationContainerTest {
-
-  @Test
-  public void componentClasses() {
-    assertThat(ComputationContainer.componentClasses()).isNotEmpty();
-  }
-}
index eaeaa3dc09fe0c4e45a9b0effd2a811ce9293196..41155fee14d93cc515c5feaf6b49669384cfede5 100644 (file)
@@ -35,7 +35,7 @@ import org.sonar.batch.protocol.Constants;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.computation.db.AnalysisReportDto;
 import org.sonar.core.computation.db.AnalysisReportDto.Status;
-import org.sonar.server.computation.activity.CEActivityManager;
+import org.sonar.server.computation.activity.ActivityManager;
 import org.sonar.server.computation.batch.BatchReportReaderRule;
 import org.sonar.server.computation.language.LanguageRepository;
 import org.sonar.server.computation.step.ComputationStep;
@@ -60,7 +60,7 @@ public class ComputationServiceTest {
   ComputationStep projectStep1 = mockStep();
   ComputationStep projectStep2 = mockStep();
   ComputationSteps steps = mock(ComputationSteps.class);
-  CEActivityManager activityManager = mock(CEActivityManager.class);
+  ActivityManager activityManager = mock(ActivityManager.class);
   System2 system = mock(System2.class);
   AnalysisReportDto dto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(Status.PENDING);
   ComputationService sut;
index 09f80a61872d9f42244e0edc01ac548b89b59838..b12880951c64bbe78ca17ec21036b89aa6d0db3e 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.sonar.server.computation;
 
+import java.util.concurrent.TimeUnit;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -28,10 +29,12 @@ import org.junit.rules.DisableOnDebug;
 import org.junit.rules.TestRule;
 import org.junit.rules.Timeout;
 import org.sonar.api.platform.Server;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.container.ContainerFactory;
 
-import java.util.concurrent.TimeUnit;
-
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 public class ComputationThreadLauncherTest {
 
@@ -40,10 +43,14 @@ public class ComputationThreadLauncherTest {
 
   ComputationThreadLauncher sut;
   ReportQueue queue;
+  ComponentContainer componentContainer;
+  ContainerFactory containerFactory;
 
   @Before
   public void before() {
     this.queue = mock(ReportQueue.class);
+    this.componentContainer = mock(ComponentContainer.class);
+    this.containerFactory = mock(ContainerFactory.class);
   }
 
   @After
@@ -53,7 +60,7 @@ public class ComputationThreadLauncherTest {
 
   @Test
   public void call_findAndBook_when_launching_a_recurrent_task() throws Exception {
-    sut = new ComputationThreadLauncher(queue, 0, 1, TimeUnit.MILLISECONDS);
+    sut = new ComputationThreadLauncher(queue, componentContainer, containerFactory, 0, 1, TimeUnit.MILLISECONDS);
 
     sut.onServerStart(mock(Server.class));
 
@@ -64,7 +71,7 @@ public class ComputationThreadLauncherTest {
 
   @Test
   public void call_findAndBook_when_executing_task_immediately() throws Exception {
-    sut = new ComputationThreadLauncher(queue, 1, 1, TimeUnit.HOURS);
+    sut = new ComputationThreadLauncher(queue, componentContainer, containerFactory, 1, 1, TimeUnit.HOURS);
     sut.start();
 
     sut.startAnalysisTaskNow();
@@ -76,7 +83,7 @@ public class ComputationThreadLauncherTest {
 
   @Test
   public void test_real_constructor() throws Exception {
-    sut = new ComputationThreadLauncher(queue);
+    sut = new ComputationThreadLauncher(queue, componentContainer);
     sut.start();
   }
 
index f3d0993db638bbd1323ab775de8a9d81a07005a5..00d3652e08a12f2a0634aa470d956f87ab344d4a 100644 (file)
 
 package org.sonar.server.computation;
 
+import java.io.IOException;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.core.computation.db.AnalysisReportDto;
-
-import java.io.IOException;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.container.ComputeEngineContainer;
+import org.sonar.server.computation.container.ContainerFactory;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
 public class ComputationThreadTest {
 
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
-
   @Rule
   public LogTester logTester = new LogTester();
 
-  ComputationContainer container = mock(ComputationContainer.class);
   ReportQueue queue = mock(ReportQueue.class);
-  ComputationThread sut = new ComputationThread(queue, container);
+  ComponentContainer componentContainer = mock(ComponentContainer.class);
+  ContainerFactory containerFactory = mock(ContainerFactory.class);
+  ComputationThread sut = new ComputationThread(queue, componentContainer, containerFactory);
 
   @Test
   public void do_nothing_if_queue_empty() {
@@ -50,19 +57,21 @@ public class ComputationThreadTest {
     sut.run();
 
     verify(queue).pop();
-    verifyZeroInteractions(container);
+    verifyZeroInteractions(containerFactory);
   }
 
   @Test
   public void pop_queue_and_integrate_report() throws IOException {
     AnalysisReportDto report = AnalysisReportDto.newForTests(1L);
     ReportQueue.Item item = new ReportQueue.Item(report, temp.newFile());
+
     when(queue.pop()).thenReturn(item);
+    when(containerFactory.create(componentContainer, item)).thenReturn(mock(ComputeEngineContainer.class));
 
     sut.run();
 
     verify(queue).pop();
-    verify(container).execute(item);
+    verify(containerFactory).create(componentContainer, item);
   }
 
   @Test
@@ -74,20 +83,10 @@ public class ComputationThreadTest {
     assertThat(logTester.logs()).contains("Failed to pop the queue of analysis reports");
   }
 
-  @Test
-  public void handle_error_during_integration() throws Exception {
-    AnalysisReportDto report = AnalysisReportDto.newForTests(1L).setProjectKey("P1");
-    ReportQueue.Item item = new ReportQueue.Item(report, temp.newFile());
-    when(queue.pop()).thenReturn(item);
-    doThrow(new IllegalStateException("pb")).when(container).execute(item);
-
-    sut.run();
-
-    assertThat(logTester.logs()).contains("Failed to process analysis report 1 of project P1");
-  }
-
   @Test
   public void handle_error_during_removal_from_queue() throws Exception {
+    when(containerFactory.create(any(ComponentContainer.class), any(ReportQueue.Item.class))).thenReturn(mock(ComputeEngineContainer.class));
+
     AnalysisReportDto report = AnalysisReportDto.newForTests(1L).setProjectKey("P1");
     ReportQueue.Item item = new ReportQueue.Item(report, temp.newFile());
     when(queue.pop()).thenReturn(item);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/activity/ActivityManagerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/activity/ActivityManagerTest.java
new file mode 100644 (file)
index 0000000..4a00b61
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.activity;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.ArgumentCaptor;
+import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.activity.Activity;
+import org.sonar.server.activity.ActivityService;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+@Category(DbTests.class)
+public class ActivityManagerTest {
+  @ClassRule
+  public static DbTester dbTester = new DbTester();
+
+  ArgumentCaptor<Activity> activityArgumentCaptor = ArgumentCaptor.forClass(Activity.class);
+
+  AnalysisReportDto reportDto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
+
+  ActivityService activityService = mock(ActivityService.class);
+  ActivityManager underTest;
+
+  @Before
+  public void setup() throws Exception {
+    dbTester.truncateTables();
+    DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao());
+
+    underTest = new ActivityManager(activityService, dbClient);
+  }
+
+  @Test
+  public void process_existing_project() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    underTest.saveActivity(reportDto);
+
+    verify(activityService).save(activityArgumentCaptor.capture());
+
+    assertThat(activityArgumentCaptor.getValue().getType()).isEqualTo(Activity.Type.ANALYSIS_REPORT);
+    assertThat(activityArgumentCaptor.getValue().getAction()).isEqualTo("LOG_ANALYSIS_REPORT");
+    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectKey", "P1");
+    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectName", "Project 1");
+    assertThat(activityArgumentCaptor.getValue().getData().get("projectUuid")).isEqualTo("ABCD");
+  }
+
+  @Test
+  public void process_new_project() throws Exception {
+    underTest.saveActivity(reportDto);
+
+    // execute only the steps supporting the project qualifier
+    verify(activityService).save(activityArgumentCaptor.capture());
+
+    assertThat(activityArgumentCaptor.getValue().getType()).isEqualTo(Activity.Type.ANALYSIS_REPORT);
+    assertThat(activityArgumentCaptor.getValue().getAction()).isEqualTo("LOG_ANALYSIS_REPORT");
+    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectKey", "P1");
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/activity/CEActivityManagerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/activity/CEActivityManagerTest.java
deleted file mode 100644 (file)
index 82b267f..0000000
+++ /dev/null
@@ -1,86 +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.activity;
-
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.mockito.ArgumentCaptor;
-import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.core.persistence.DbTester;
-import org.sonar.server.activity.Activity;
-import org.sonar.server.activity.ActivityService;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-@Category(DbTests.class)
-public class CEActivityManagerTest {
-  @ClassRule
-  public static DbTester dbTester = new DbTester();
-
-  ArgumentCaptor<Activity> activityArgumentCaptor = ArgumentCaptor.forClass(Activity.class);
-
-  AnalysisReportDto reportDto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
-
-  ActivityService activityService = mock(ActivityService.class);
-  CEActivityManager underTest;
-
-  @Before
-  public void setup() throws Exception {
-    dbTester.truncateTables();
-    DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao());
-
-    underTest = new CEActivityManager(activityService, dbClient);
-  }
-
-  @Test
-  public void process_existing_project() throws Exception {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    underTest.saveActivity(reportDto);
-
-    verify(activityService).save(activityArgumentCaptor.capture());
-
-    assertThat(activityArgumentCaptor.getValue().getType()).isEqualTo(Activity.Type.ANALYSIS_REPORT);
-    assertThat(activityArgumentCaptor.getValue().getAction()).isEqualTo("LOG_ANALYSIS_REPORT");
-    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectKey", "P1");
-    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectName", "Project 1");
-    assertThat(activityArgumentCaptor.getValue().getData().get("projectUuid")).isEqualTo("ABCD");
-  }
-
-  @Test
-  public void process_new_project() throws Exception {
-    underTest.saveActivity(reportDto);
-
-    // execute only the steps supporting the project qualifier
-    verify(activityService).save(activityArgumentCaptor.capture());
-
-    assertThat(activityArgumentCaptor.getValue().getType()).isEqualTo(Activity.Type.ANALYSIS_REPORT);
-    assertThat(activityArgumentCaptor.getValue().getAction()).isEqualTo("LOG_ANALYSIS_REPORT");
-    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectKey", "P1");
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/container/ComputeEngineContainerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/container/ComputeEngineContainerImplTest.java
new file mode 100644 (file)
index 0000000..389e3d3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.container;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import java.util.Set;
+import org.junit.Test;
+import org.picocontainer.ComponentAdapter;
+import org.reflections.Reflections;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.step.ComputationStep;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ComputeEngineContainerImplTest {
+  @Test(expected = NullPointerException.class)
+  public void constructor_fails_fast_on_null_container() {
+    new ComputeEngineContainerImpl(null, mock(ReportQueue.Item.class));
+  }
+  @Test(expected = NullPointerException.class)
+  public void constructor_fails_fast_on_null_item() {
+    new ComputeEngineContainerImpl(new ComponentContainer(), null);
+  }
+
+  @Test
+  public void ce_container_is_not_child_of_specified_container() {
+    ComponentContainer parent = new ComponentContainer();
+    ComputeEngineContainerImpl ceContainer = new ComputeEngineContainerImpl(parent, mock(ReportQueue.Item.class));
+
+    assertThat(parent.getChild()).isNull();
+    assertThat(parent.getPicoContainer().removeChildContainer(ceContainer.getPicoContainer())).isFalse();
+  }
+
+  @Test
+  public void all_steps_from_package_step_are_present_in_container() {
+    ComputeEngineContainerImpl ceContainer = new ComputeEngineContainerImpl(new ComponentContainer(), mock(ReportQueue.Item.class));
+
+    Set<String> stepsCanonicalNames = retrieveStepPackageStepsCanonicalNames();
+
+    Set<String> typesInContainer = Sets.newHashSet(
+      Iterables.transform(
+        Iterables.filter(
+          Iterables.transform(
+            ceContainer.getPicoContainer().getComponentAdapters(),
+            ComponentAdapterToImplementationClass.INSTANCE),
+          IsComputationStep.INSTANCE),
+        ClassToCanonicalName.INSTANCE));
+
+    assertThat(typesInContainer).isEqualTo(stepsCanonicalNames);
+  }
+
+  /**
+   * Compute set of canonical names of classes implementing ComputationStep in package step using reflection.
+   */
+  private Set<String> retrieveStepPackageStepsCanonicalNames() {
+    Reflections reflections = new Reflections("org.sonar.server.computation.step");
+
+    return Sets.newHashSet(Iterables.transform(reflections.getSubTypesOf(ComputationStep.class), ClassToCanonicalName.INSTANCE));
+  }
+
+  private enum ClassToCanonicalName implements Function<Class<?>, String> {
+    INSTANCE;
+
+    @Override
+    public String apply(Class<?> input) {
+      return input.getCanonicalName();
+    }
+  }
+
+  private enum ComponentAdapterToImplementationClass implements Function<ComponentAdapter<?>, Class<?>> {
+    INSTANCE;
+
+    @Override
+    public Class<?> apply(ComponentAdapter<?> input) {
+      return input.getComponentImplementation();
+    }
+  }
+
+  private enum IsComputationStep implements Predicate<Class<?>> {
+    INSTANCE;
+
+    @Override
+    public boolean apply(Class<?> input) {
+      return ComputationStep.class.isAssignableFrom(input);
+    }
+  }
+}
index 72cf7bb897b4c5634e928a1e04b9fe940375d254..bc254a287478d00b664aaf803b4eefd7ca86606f 100644 (file)
 
 package org.sonar.server.computation.step;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-import java.util.List;
+import com.google.common.collect.Sets;
+import java.util.Set;
 import org.junit.Test;
+import org.picocontainer.ComponentAdapter;
+import org.reflections.Reflections;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.container.CEContainer;
+import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.container.ComputeEngineContainerImpl;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
@@ -32,48 +39,67 @@ import static org.mockito.Mockito.mock;
 
 public class ComputationStepsTest {
 
-  @Test
-  public void ordered_steps() {
-    CEContainer ceContainer = new CEContainer(new ComponentContainer());
-    ceContainer.add(
-      // unordered
-      mock(ApplyPermissionsStep.class),
-      mock(ParseReportStep.class),
-      mock(IndexSourceLinesStep.class),
-      mock(PersistIssuesStep.class),
-      mock(IndexIssuesStep.class),
-      mock(SwitchSnapshotStep.class),
-      mock(PurgeDatastoresStep.class),
-      mock(SendIssueNotificationsStep.class),
-      mock(IndexComponentsStep.class),
-      mock(PersistProjectLinksStep.class),
-      mock(PersistMeasuresStep.class),
-      mock(PersistEventsStep.class),
-      mock(PersistDuplicationsStep.class),
-      mock(PersistNumberOfDaysSinceLastCommitStep.class),
-      mock(PersistFileSourcesStep.class),
-      mock(PersistTestsStep.class),
-      mock(IndexTestsStep.class),
-      mock(PopulateComponentsUuidAndKeyStep.class),
-      mock(PersistComponentsStep.class),
-      mock(QualityProfileEventsStep.class),
-      mock(ValidateProjectStep.class)
-      );
-    ComputationSteps computationSteps = new ComputationSteps(ceContainer);
-
-    List<ComputationStep> steps = Lists.newArrayList(computationSteps.instances());
-    assertThat(steps).hasSize(21);
-    assertThat(steps.get(0)).isInstanceOf(PopulateComponentsUuidAndKeyStep.class);
-    assertThat(steps.get(20)).isInstanceOf(SendIssueNotificationsStep.class);
-  }
-
   @Test
   public void fail_if_a_step_is_not_registered_in_picocontainer() {
     try {
-      Lists.newArrayList(new ComputationSteps(new CEContainer(new ComponentContainer())).instances());
+      Lists.newArrayList(new ComputationSteps(mock(ComputeEngineContainerImpl.class)).instances());
       fail();
     } catch (IllegalStateException e) {
       assertThat(e).hasMessageContaining("Component not found");
     }
   }
+
+  @Test
+  public void all_steps_from_package_step_are_present_in_container() {
+    ComputeEngineContainerImpl ceContainer = new ComputeEngineContainerImpl(new ComponentContainer(), mock(ReportQueue.Item.class));
+
+    Set<String> stepsCanonicalNames = retrieveStepPackageStepsCanonicalNames();
+
+    Set<String> typesInContainer = Sets.newHashSet(
+        Iterables.transform(
+            Iterables.filter(
+                Iterables.transform(
+                    ceContainer.getPicoContainer().getComponentAdapters(),
+                    ComponentAdapterToImplementationClass.INSTANCE),
+                IsComputationStep.INSTANCE),
+            ClassToCanonicalName.INSTANCE));
+
+    assertThat(typesInContainer).isEqualTo(stepsCanonicalNames);
+  }
+
+  /**
+   * Compute set of canonical names of classes implementing ComputationStep in package step using reflection.
+   */
+  private Set<String> retrieveStepPackageStepsCanonicalNames() {
+    Reflections reflections = new Reflections("org.sonar.server.computation.step");
+
+    return Sets.newHashSet(Iterables.transform(reflections.getSubTypesOf(ComputationStep.class), ClassToCanonicalName.INSTANCE));
+  }
+
+  private enum ClassToCanonicalName implements Function<Class<?>, String> {
+    INSTANCE;
+
+    @Override
+    public String apply(Class<?> input) {
+      return input.getCanonicalName();
+    }
+  }
+
+  private enum ComponentAdapterToImplementationClass implements Function<ComponentAdapter<?>, Class<?>> {
+    INSTANCE;
+
+    @Override
+    public Class<?> apply(ComponentAdapter<?> input) {
+      return input.getComponentImplementation();
+    }
+  }
+
+  private enum IsComputationStep implements Predicate<Class<?>> {
+    INSTANCE;
+
+    @Override
+    public boolean apply(Class<?> input) {
+      return ComputationStep.class.isAssignableFrom(input);
+    }
+  }
 }
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/activity/ActivityManagerTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/activity/ActivityManagerTest/shared.xml
new file mode 100644 (file)
index 0000000..2ac38c2
--- /dev/null
@@ -0,0 +1,11 @@
+<dataset>
+  <projects id="10" kee="P1" qualifier="TRK" uuid="ABCD" name="Project 1"/>
+  <snapshots
+      id="110" project_id="10" parent_snapshot_id="[null]" root_project_id="10" root_snapshot_id="[null]"
+      purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+      period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
+      period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
+      period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+      scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000" version="[null]" path=""
+      status="P" islast="[false]" depth="0"/>
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/activity/CEActivityManagerTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/activity/CEActivityManagerTest/shared.xml
deleted file mode 100644 (file)
index 2ac38c2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<dataset>
-  <projects id="10" kee="P1" qualifier="TRK" uuid="ABCD" name="Project 1"/>
-  <snapshots
-      id="110" project_id="10" parent_snapshot_id="[null]" root_project_id="10" root_snapshot_id="[null]"
-      purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
-      period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]"
-      period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]"
-      period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]"
-      scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000" version="[null]" path=""
-      status="P" islast="[false]" depth="0"/>
-</dataset>
index e0bafcf8e9c179eeb94a173d83702f3d7fbe1ae7..d6a2a258a759bd2ebd08b00097a21dcf86b8d342 100644 (file)
@@ -50,9 +50,13 @@ public class ComponentContainer {
    * Create root container
    */
   public ComponentContainer() {
+    this(createPicoContainer());
+  }
+
+  protected ComponentContainer(MutablePicoContainer picoContainer) {
     this.parent = null;
     this.child = null;
-    this.pico = createPicoContainer();
+    this.pico = picoContainer;
     this.componentKeys = new ComponentKeys();
     propertyDefinitions = new PropertyDefinitions();
     addSingleton(propertyDefinitions);
@@ -63,15 +67,8 @@ public class ComponentContainer {
    * Create child container
    */
   protected ComponentContainer(ComponentContainer parent) {
-    this(parent.pico.makeChildContainer(), parent);
-  }
-
-  /**
-   * Create child container
-   */
-  protected ComponentContainer(MutablePicoContainer picoContainer, ComponentContainer parent) {
     this.parent = parent;
-    this.pico = picoContainer;
+    this.pico = parent.pico.makeChildContainer();
     this.parent.child = this;
     this.propertyDefinitions = parent.propertyDefinitions;
     this.componentKeys = new ComponentKeys();
@@ -216,8 +213,8 @@ public class ComponentContainer {
     return this;
   }
 
-  public <T> T getComponentByType(Class<T> tClass) {
-    return pico.getComponent(tClass);
+  public <T> T getComponentByType(Class<T> type) {
+    return pico.getComponent(type);
   }
 
   public Object getComponentByKey(Object key) {