]> source.dussan.org Git - sonarqube.git/commitdiff
Introduce concept of module
authorEvgeny Mandrikov <mandrikov@gmail.com>
Mon, 21 Feb 2011 20:08:22 +0000 (23:08 +0300)
committerEvgeny Mandrikov <mandrikov@gmail.com>
Mon, 21 Feb 2011 23:24:16 +0000 (02:24 +0300)
sonar-batch/src/main/java/org/sonar/batch/Batch.java
sonar-batch/src/main/java/org/sonar/batch/Module.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java

index e95f6ee29279c6b3d818a5601a8c04557241f713..36a702073cde9a46c02111ac7734284878c9e010 100644 (file)
  */
 package org.sonar.batch;
 
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
 import org.apache.commons.configuration.Configuration;
-import org.picocontainer.Characteristics;
-import org.picocontainer.MutablePicoContainer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.Plugins;
 import org.sonar.api.resources.Project;
 import org.sonar.api.utils.HttpDownloader;
-import org.sonar.api.utils.IocContainer;
 import org.sonar.api.utils.ServerHttpClient;
 import org.sonar.batch.bootstrap.BatchPluginRepository;
 import org.sonar.batch.bootstrap.BootstrapClassLoader;
@@ -43,9 +43,6 @@ import org.sonar.jpa.session.DatabaseSessionProvider;
 import org.sonar.jpa.session.DriverDatabaseConnector;
 import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
 
-import java.net.URLClassLoader;
-import java.util.Arrays;
-
 public class Batch {
 
   private static final Logger LOG = LoggerFactory.getLogger(Batch.class);
@@ -59,79 +56,82 @@ public class Batch {
   }
 
   public void execute() {
-    MutablePicoContainer container = null;
+    Module bootstrapComponents = null;
     try {
-      container = buildPicoContainer();
-      container.start();
-      analyzeModules(container);
-
+      bootstrapComponents = new BootstrapComponents().init().start();
+      analyzeModules(bootstrapComponents);
     } finally {
-      if (container != null) {
-        container.stop();
+      if (bootstrapComponents != null) {
+        bootstrapComponents.stop();
       }
     }
   }
 
-  private void analyzeModules(MutablePicoContainer container) {
-    // a child container is built to ensure database connector is up
-    MutablePicoContainer batchContainer = container.makeChildContainer();
-    batchContainer.as(Characteristics.CACHE).addComponent(ProjectTree.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultResourceCreationLock.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultIndex.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultPersistenceManager.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DependencyPersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(EventPersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(LinkPersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(MeasurePersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultResourcePersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(SourcePersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(ViolationPersister.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(JpaPluginDao.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(BatchPluginRepository.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(Plugins.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(ServerHttpClient.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(MeasuresDao.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(CacheRuleFinder.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(CacheMetricFinder.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastSnapshotFinderByDate.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastSnapshotFinderByDays.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastSnapshotFinderByPreviousAnalysis.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastSnapshotFinderByVersion.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastMeasuresLoader.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastSnapshotFinder.class);
-    batchContainer.start();
-
-    ProjectTree projectTree = batchContainer.getComponent(ProjectTree.class);
-    DefaultIndex index = batchContainer.getComponent(DefaultIndex.class);
-    analyzeModule(batchContainer, index, projectTree.getRootProject());
+  private void analyzeModules(Module bootstrapComponents) {
+    Module batchComponents = bootstrapComponents.installChild(new BatchComponents());
+    batchComponents.start();
+
+    ProjectTree projectTree = batchComponents.getComponent(ProjectTree.class);
+    DefaultIndex index = batchComponents.getComponent(DefaultIndex.class);
+    analyzeModule(batchComponents, index, projectTree.getRootProject());
 
     // batchContainer is stopped by its parent
   }
 
-  private MutablePicoContainer buildPicoContainer() {
-    MutablePicoContainer container = IocContainer.buildPicoContainer();
-
-    register(container, configuration);
-    register(container, ServerMetadata.class);// registered here because used by BootstrapClassLoader
-    register(container, TempDirectories.class);// registered here because used by BootstrapClassLoader
-    register(container, HttpDownloader.class);// registered here because used by BootstrapClassLoader
-    register(container, ExtensionDownloader.class);// registered here because used by BootstrapClassLoader
-    register(container, BootstrapClassLoader.class);
-
-    URLClassLoader bootstrapClassLoader = container.getComponent(BootstrapClassLoader.class).getClassLoader();
-    // set as the current context classloader for hibernate, else it does not find the JDBC driver.
-    Thread.currentThread().setContextClassLoader(bootstrapClassLoader);
-
-    register(container, new DriverDatabaseConnector(configuration, bootstrapClassLoader));
-    register(container, ThreadLocalDatabaseSessionFactory.class);
-    container.as(Characteristics.CACHE).addAdapter(new DatabaseSessionProvider());
-    for (Object component : components) {
-      register(container, component);
+  private static class BatchComponents extends Module {
+    @Override
+    protected void configure() {
+      addComponent(ProjectTree.class);
+      addComponent(DefaultResourceCreationLock.class);
+      addComponent(DefaultIndex.class);
+      addComponent(DefaultPersistenceManager.class);
+      addComponent(DependencyPersister.class);
+      addComponent(EventPersister.class);
+      addComponent(LinkPersister.class);
+      addComponent(MeasurePersister.class);
+      addComponent(DefaultResourcePersister.class);
+      addComponent(SourcePersister.class);
+      addComponent(ViolationPersister.class);
+      addComponent(JpaPluginDao.class);
+      addComponent(BatchPluginRepository.class);
+      addComponent(Plugins.class);
+      addComponent(ServerHttpClient.class);
+      addComponent(MeasuresDao.class);
+      addComponent(CacheRuleFinder.class);
+      addComponent(CacheMetricFinder.class);
+      addComponent(PastSnapshotFinderByDate.class);
+      addComponent(PastSnapshotFinderByDays.class);
+      addComponent(PastSnapshotFinderByPreviousAnalysis.class);
+      addComponent(PastSnapshotFinderByVersion.class);
+      addComponent(PastMeasuresLoader.class);
+      addComponent(PastSnapshotFinder.class);
     }
-    if (!isMavenPluginExecutorRegistered()) {
-      register(container, FakeMavenPluginExecutor.class);
+  }
+
+  private class BootstrapComponents extends Module {
+    @Override
+    protected void configure() {
+      addComponent(configuration);
+      addComponent(ServerMetadata.class);// registered here because used by BootstrapClassLoader
+      addComponent(TempDirectories.class);// registered here because used by BootstrapClassLoader
+      addComponent(HttpDownloader.class);// registered here because used by BootstrapClassLoader
+      addComponent(ExtensionDownloader.class);// registered here because used by BootstrapClassLoader
+      addComponent(BootstrapClassLoader.class);
+
+      URLClassLoader bootstrapClassLoader = getComponent(BootstrapClassLoader.class).getClassLoader();
+      // set as the current context classloader for hibernate, else it does not find the JDBC driver.
+      Thread.currentThread().setContextClassLoader(bootstrapClassLoader);
+
+      addComponent(new DriverDatabaseConnector(configuration, bootstrapClassLoader));
+      addComponent(ThreadLocalDatabaseSessionFactory.class);
+      addAdapter(new DatabaseSessionProvider());
+      for (Object component : components) {
+        addComponent(component);
+      }
+      if (!isMavenPluginExecutorRegistered()) {
+        addComponent(FakeMavenPluginExecutor.class);
+      }
     }
-    return container;
   }
 
   boolean isMavenPluginExecutorRegistered() {
@@ -143,13 +143,9 @@ public class Batch {
     return false;
   }
 
-  private void register(MutablePicoContainer container, Object component) {
-    container.as(Characteristics.CACHE).addComponent(component);
-  }
-
-  private void analyzeModule(MutablePicoContainer container, DefaultIndex index, Project project) {
+  private void analyzeModule(Module batchComponents, DefaultIndex index, Project project) {
     for (Project module : project.getModules()) {
-      analyzeModule(container, index, module);
+      analyzeModule(batchComponents, index, module);
     }
     LOG.info("-------------  Analyzing {}", project.getName());
 
@@ -158,6 +154,6 @@ public class Batch {
       LOG.info("Excluded sources : {}", Arrays.toString(exclusionPatterns));
     }
 
-    new ProjectBatch(container).execute(index, project);
+    new ProjectBatch(batchComponents).execute(index, project);
   }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/Module.java b/sonar-batch/src/main/java/org/sonar/batch/Module.java
new file mode 100644 (file)
index 0000000..73f4b2b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.batch;
+
+import java.util.List;
+
+import org.picocontainer.Characteristics;
+import org.picocontainer.ComponentAdapter;
+import org.picocontainer.MutablePicoContainer;
+import org.sonar.api.utils.IocContainer;
+
+/**
+ * Module describes group of components - {@link #configure()}.
+ * Several modules can be grouped together - {@link #install(Module)}, {@link #installChild(Module)}.
+ */
+public abstract class Module {
+
+  private MutablePicoContainer container;
+
+  /**
+   * @return this
+   */
+  public final Module init() {
+    this.container = IocContainer.buildPicoContainer();
+    configure();
+    return this;
+  }
+
+  /**
+   * @return this
+   */
+  private final Module init(MutablePicoContainer container) {
+    this.container = container;
+    configure();
+    return this;
+  }
+
+  /**
+   * Installs module into this module.
+   * 
+   * @return this
+   */
+  public final Module install(Module module) {
+    module.init(container);
+    return this;
+  }
+
+  /**
+   * Installs module into new scope - see http://picocontainer.org/scopes.html
+   * 
+   * @return installed module
+   */
+  public final Module installChild(Module module) {
+    MutablePicoContainer child = container.makeChildContainer();
+    // register container as a component, because it used for example in BatchExtensionDictionnary,
+    // but in fact this is anti-pattern - http://picocontainer.codehaus.org/container-dependency-antipattern.html
+    child.addComponent(new IocContainer(child));
+    child.setName(module.toString());
+    module.init(child);
+    return module;
+  }
+
+  public final void uninstallChild(Module module) {
+    container.removeChildContainer(module.container);
+  }
+
+  /**
+   * @return this
+   */
+  public Module start() {
+    container.start();
+    return this;
+  }
+
+  /**
+   * @return this
+   */
+  public Module stop() {
+    container.stop();
+    return this;
+  }
+
+  /**
+   * Implementation of this method must not contain conditional logic and just should contain several invocations of
+   * {@link #addComponent(Object)}, {@link #addComponent(Object, Object)} or {@link #addAdapter(ComponentAdapter)}.
+   */
+  protected abstract void configure();
+
+  protected final void addComponent(Object component) {
+    container.as(Characteristics.CACHE).addComponent(component);
+  }
+
+  protected final void addComponent(Object componentKey, Object component) {
+    container.as(Characteristics.CACHE).addComponent(componentKey, component);
+  }
+
+  protected final void addAdapter(ComponentAdapter<?> componentAdapter) {
+    container.addAdapter(componentAdapter);
+  }
+
+  protected final <T> T getComponent(Class<T> componentType) {
+    return container.getComponent(componentType);
+  }
+
+  protected final <T> List<T> getComponents(Class<T> componentType) {
+    return container.getComponents(componentType);
+  }
+
+  /**
+   * @TODO should not be used and should be removed
+   */
+  public final MutablePicoContainer getContainer() {
+    return container;
+  }
+
+}
index 1cd325a55090f5911522896347ebd44b73bd1df1..575be37f35abaf20f67b14b152b898b38ba991af 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.batch;
 
-import org.picocontainer.Characteristics;
-import org.picocontainer.MutablePicoContainer;
 import org.sonar.api.batch.BatchExtensionDictionnary;
 import org.sonar.api.batch.ProjectClasspath;
 import org.sonar.api.measures.CoreMetrics;
@@ -29,7 +27,6 @@ import org.sonar.api.measures.Metrics;
 import org.sonar.api.profiles.RulesProfile;
 import org.sonar.api.resources.*;
 import org.sonar.api.rules.DefaultRulesManager;
-import org.sonar.api.utils.IocContainer;
 import org.sonar.api.utils.SonarException;
 import org.sonar.batch.bootstrap.BatchPluginRepository;
 import org.sonar.batch.components.PastViolationsLoader;
@@ -42,114 +39,117 @@ import org.sonar.jpa.dao.*;
 
 public class ProjectBatch {
 
-  private MutablePicoContainer globalContainer;
-  private MutablePicoContainer batchContainer;
+  private Module globalComponents;
 
-  public ProjectBatch(MutablePicoContainer container) {
-    this.globalContainer = container;
+  public ProjectBatch(Module globalComponents) {
+    this.globalComponents = globalComponents;
   }
 
   public void execute(DefaultIndex index, Project project) {
+    Module projectComponents = null;
     try {
-      startChildContainer(index, project);
-      batchContainer.getComponent(Phases.class).execute(project);
+      projectComponents = startChildContainer(index, project);
+
+      projectComponents.getComponent(Phases.class).execute(project);
 
     } finally {
-      stop();
+      if (projectComponents != null) {
+        try {
+          globalComponents.uninstallChild(projectComponents);
+          projectComponents.stop();
+        } catch (Exception e) {
+          // do not log
+        }
+      }
     }
   }
 
-  public void startChildContainer(DefaultIndex index, Project project) {
-    batchContainer = globalContainer.makeChildContainer();
-
-    batchContainer.as(Characteristics.CACHE).addComponent(project);
-    batchContainer.as(Characteristics.CACHE).addComponent(project.getPom());
-    batchContainer.as(Characteristics.CACHE).addComponent(ProjectClasspath.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultProjectFileSystem.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(project.getConfiguration());
-
-    // need to be registered after the Configuration
-    batchContainer.getComponent(BatchPluginRepository.class).registerPlugins(batchContainer);
-
-    batchContainer.as(Characteristics.CACHE).addComponent(DaoFacade.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(RulesDao.class);
-
-    // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
-    batchContainer.as(Characteristics.CACHE)
-        .addComponent(globalContainer.getComponent(DefaultResourcePersister.class).getSnapshot(project));
-
-    batchContainer.as(Characteristics.CACHE).addComponent(org.sonar.api.database.daos.MeasuresDao.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(ProfilesDao.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(AsyncMeasuresDao.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(AsyncMeasuresService.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultRulesManager.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultSensorContext.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(Languages.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(BatchExtensionDictionnary.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultTimeMachine.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(ViolationFilters.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(ResourceFilters.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(DefaultModelFinder.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(TimeMachineConfiguration.class);
-    batchContainer.as(Characteristics.CACHE).addComponent(PastViolationsLoader.class);
-    batchContainer.addAdapter(new ProfileProvider());
-    batchContainer.addAdapter(new CheckProfileProvider());
-    loadCoreComponents(batchContainer);
-    batchContainer.as(Characteristics.CACHE).addComponent(new IocContainer(batchContainer));
-    batchContainer.start();
+  public Module startChildContainer(DefaultIndex index, Project project) {
+    Module projectComponents = globalComponents.installChild(new ProjectComponents(project));
+    projectComponents.install(new ProjectCoreComponents());
+    projectComponents.start();
 
     // post-initializations
-    prepareProject(project, index);
-  }
 
-  private void prepareProject(Project project, DefaultIndex index) {
-    Language language = getComponent(Languages.class).get(project.getLanguageKey());
+    Language language = projectComponents.getComponent(Languages.class).get(project.getLanguageKey());
     if (language == null) {
       throw new SonarException("Language with key '" + project.getLanguageKey() + "' not found");
     }
     project.setLanguage(language);
 
     index.setCurrentProject(project,
-        getComponent(ResourceFilters.class),
-        getComponent(ViolationFilters.class),
-        getComponent(RulesProfile.class));
+        projectComponents.getComponent(ResourceFilters.class),
+        projectComponents.getComponent(ViolationFilters.class),
+        projectComponents.getComponent(RulesProfile.class));
 
     // TODO See http://jira.codehaus.org/browse/SONAR-2126
     // previously MavenProjectBuilder was responsible for creation of ProjectFileSystem
-    project.setFileSystem(getComponent(ProjectFileSystem.class));
+    project.setFileSystem(projectComponents.getComponent(ProjectFileSystem.class));
+
+    return projectComponents;
   }
 
-  private void loadCoreComponents(MutablePicoContainer container) {
-    container.as(Characteristics.CACHE).addComponent(Phases.class);
-    for (Class clazz : Phases.getPhaseClasses()) {
-      container.as(Characteristics.CACHE).addComponent(clazz);
-    }
-    for (Metric metric : CoreMetrics.getMetrics()) {
-      container.as(Characteristics.CACHE).addComponent(metric.getKey(), metric);
+  private static class ProjectComponents extends Module {
+    private Project project;
+
+    public ProjectComponents(Project project) {
+      this.project = project;
     }
-    for (Metrics metricRepo : container.getComponents(Metrics.class)) {
-      for (Metric metric : metricRepo.getMetrics()) {
-        container.as(Characteristics.CACHE).addComponent(metric.getKey(), metric);
-      }
+
+    @Override
+    protected void configure() {
+      addComponent(project);
+      addComponent(project.getPom());
+      addComponent(ProjectClasspath.class);
+      addComponent(DefaultProjectFileSystem.class);
+      addComponent(project.getConfiguration());
+
+      // need to be registered after the Configuration
+      getComponent(BatchPluginRepository.class).registerPlugins(getContainer());
+
+      addComponent(DaoFacade.class);
+      addComponent(RulesDao.class);
+
+      // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
+      addComponent(getComponent(DefaultResourcePersister.class).getSnapshot(project));
+      // TODO was addComponent(globalComponents.getComponent(DefaultResourcePersister.class).getSnapshot(project));
+
+      addComponent(org.sonar.api.database.daos.MeasuresDao.class);
+      addComponent(ProfilesDao.class);
+      addComponent(AsyncMeasuresDao.class);
+      addComponent(AsyncMeasuresService.class);
+      addComponent(DefaultRulesManager.class);
+      addComponent(DefaultSensorContext.class);
+      addComponent(Languages.class);
+      addComponent(BatchExtensionDictionnary.class);
+      addComponent(DefaultTimeMachine.class);
+      addComponent(ViolationFilters.class);
+      addComponent(ResourceFilters.class);
+      addComponent(DefaultModelFinder.class);
+      addComponent(TimeMachineConfiguration.class);
+      addComponent(PastViolationsLoader.class);
+
+      addAdapter(new ProfileProvider());
+      addAdapter(new CheckProfileProvider());
     }
   }
 
-  private void stop() {
-    if (batchContainer != null) {
-      try {
-        globalContainer.removeChildContainer(batchContainer);
-        batchContainer.stop();
-        batchContainer = null;
-      } catch (Exception e) {
-        // do not log
+  private static class ProjectCoreComponents extends Module {
+    @Override
+    protected void configure() {
+      addComponent(Phases.class);
+      for (Class clazz : Phases.getPhaseClasses()) {
+        addComponent(clazz);
+      }
+      for (Metric metric : CoreMetrics.getMetrics()) {
+        addComponent(metric.getKey(), metric);
+      }
+      for (Metrics metricRepo : getComponents(Metrics.class)) {
+        for (Metric metric : metricRepo.getMetrics()) {
+          addComponent(metric.getKey(), metric);
+        }
       }
     }
   }
 
-  public <T> T getComponent(Class<T> clazz) {
-    if (batchContainer != null) {
-      return batchContainer.getComponent(clazz);
-    }
-    return globalContainer.getComponent(clazz);
-  }
 }