From e52812f9f07dec51f17e740568ae7cd0dade1d53 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 21 Feb 2011 23:08:22 +0300 Subject: [PATCH] Introduce concept of module --- .../src/main/java/org/sonar/batch/Batch.java | 144 ++++++++-------- .../src/main/java/org/sonar/batch/Module.java | 133 ++++++++++++++ .../java/org/sonar/batch/ProjectBatch.java | 162 +++++++++--------- 3 files changed, 284 insertions(+), 155 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/Module.java diff --git a/sonar-batch/src/main/java/org/sonar/batch/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/Batch.java index e95f6ee2927..36a702073cd 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/Batch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/Batch.java @@ -19,15 +19,15 @@ */ 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 index 00000000000..73f4b2b0ed9 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/Module.java @@ -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 getComponent(Class componentType) { + return container.getComponent(componentType); + } + + protected final List getComponents(Class componentType) { + return container.getComponents(componentType); + } + + /** + * @TODO should not be used and should be removed + */ + public final MutablePicoContainer getContainer() { + return container; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java b/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java index 1cd325a5509..575be37f35a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java @@ -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 getComponent(Class clazz) { - if (batchContainer != null) { - return batchContainer.getComponent(clazz); - } - return globalContainer.getComponent(clazz); - } } -- 2.39.5