aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-03-14 23:17:22 +0100
committerSimon Brandhof <simon.brandhof@gmail.com>2013-03-14 23:17:22 +0100
commitc2eab2217274ce151f2a330348d649997c278d03 (patch)
tree12fc44f7f1aba23e1a280f57d7b2e4c12a16f4a4
parent3f4f0ba6cd0380e1f918aa3d85eb0e1271775905 (diff)
downloadsonarqube-c2eab2217274ce151f2a330348d649997c278d03.tar.gz
sonarqube-c2eab2217274ce151f2a330348d649997c278d03.zip
Improve exception handling of pico container lifecycle
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java105
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java43
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java42
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java91
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java66
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java13
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java28
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java78
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/platform/PicoUtils.java (renamed from sonar-core/src/main/java/org/sonar/core/PicoUtils.java)9
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java79
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/platform/PicoUtilsTest.java (renamed from sonar-core/src/test/java/org/sonar/core/PicoUtilsTest.java)39
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java11
12 files changed, 343 insertions, 261 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
index eb808e74ed6..d8491e18758 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
@@ -33,6 +33,8 @@ import org.sonar.batch.components.PastSnapshotFinderByDays;
import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis;
import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion;
import org.sonar.batch.components.PastSnapshotFinderByVersion;
+import org.sonar.batch.scan.ScanTask;
+import org.sonar.batch.tasks.ListTask;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.I18nManager;
import org.sonar.core.i18n.RuleI18nManager;
@@ -60,6 +62,12 @@ public class BootstrapContainer extends ComponentContainer {
super();
}
+ public static BootstrapContainer create(List objects) {
+ BootstrapContainer container = new BootstrapContainer();
+ container.add(objects);
+ return container;
+ }
+
@Override
protected void doBeforeStart() {
addBootstrapComponents();
@@ -69,36 +77,36 @@ public class BootstrapContainer extends ComponentContainer {
private void addBootstrapComponents() {
add(
- new PropertiesConfiguration(),
- BootstrapSettings.class,
- PluginDownloader.class,
- BatchPluginRepository.class,
- BatchSettings.class,
- ServerClient.class,
- ExtensionInstaller.class,
- Logback.class,
- ServerMetadata.class,
- org.sonar.batch.ServerMetadata.class,
- TempDirectories.class,
- HttpDownloader.class,
- UriReader.class,
- new FileCacheProvider()
+ new PropertiesConfiguration(),
+ BootstrapSettings.class,
+ PluginDownloader.class,
+ BatchPluginRepository.class,
+ BatchSettings.class,
+ ServerClient.class,
+ ExtensionInstaller.class,
+ Logback.class,
+ ServerMetadata.class,
+ org.sonar.batch.ServerMetadata.class,
+ TempDirectories.class,
+ HttpDownloader.class,
+ UriReader.class,
+ new FileCacheProvider()
);
}
private void addDatabaseComponents() {
add(
- DryRunDatabase.class,
- JdbcDriverHolder.class,
- BatchDatabase.class,
- MyBatis.class,
- DatabaseVersion.class,
- //TODO check that it still works (see @Freddy)
- DatabaseCompatibility.class,
- DefaultDatabaseConnector.class,
- JpaDatabaseSession.class,
- BatchDatabaseSessionFactory.class,
- DaoUtils.getDaoClasses()
+ DryRunDatabase.class,
+ JdbcDriverHolder.class,
+ BatchDatabase.class,
+ MyBatis.class,
+ DatabaseVersion.class,
+ //TODO check that it still works (see @Freddy)
+ DatabaseCompatibility.class,
+ DefaultDatabaseConnector.class,
+ JpaDatabaseSession.class,
+ BatchDatabaseSessionFactory.class,
+ DaoUtils.getDaoClasses()
);
}
@@ -107,44 +115,43 @@ public class BootstrapContainer extends ComponentContainer {
*/
private void addCoreComponents() {
add(
- EmailSettings.class,
- I18nManager.class,
- RuleI18nManager.class,
- MeasuresDao.class,
- RulesDao.class,
- ProfilesDao.class,
- CacheRuleFinder.class,
- CacheMetricFinder.class,
- DefaultUserFinder.class,
- SemaphoreUpdater.class,
- SemaphoresImpl.class,
- PastSnapshotFinderByDate.class,
- PastSnapshotFinderByDays.class,
- PastSnapshotFinderByPreviousAnalysis.class,
- PastSnapshotFinderByVersion.class,
- PastSnapshotFinderByPreviousVersion.class,
- PastMeasuresLoader.class,
- PastSnapshotFinder.class,
- DefaultModelFinder.class
+ EmailSettings.class,
+ I18nManager.class,
+ RuleI18nManager.class,
+ MeasuresDao.class,
+ RulesDao.class,
+ ProfilesDao.class,
+ CacheRuleFinder.class,
+ CacheMetricFinder.class,
+ DefaultUserFinder.class,
+ SemaphoreUpdater.class,
+ SemaphoresImpl.class,
+ PastSnapshotFinderByDate.class,
+ PastSnapshotFinderByDays.class,
+ PastSnapshotFinderByPreviousAnalysis.class,
+ PastSnapshotFinderByVersion.class,
+ PastSnapshotFinderByPreviousVersion.class,
+ PastMeasuresLoader.class,
+ PastSnapshotFinder.class,
+ DefaultModelFinder.class
);
}
@Override
protected void doAfterStart() {
installPlugins();
+ executeTask();
}
private void installPlugins() {
- for (Map.Entry<PluginMetadata, Plugin> entry : get(BatchPluginRepository.class).getPluginsByMetadata().entrySet()) {
+ for (Map.Entry<PluginMetadata, Plugin> entry : getComponentByType(BatchPluginRepository.class).getPluginsByMetadata().entrySet()) {
PluginMetadata metadata = entry.getKey();
Plugin plugin = entry.getValue();
addExtension(metadata, plugin);
}
}
- public static BootstrapContainer create(List objects) {
- BootstrapContainer container = new BootstrapContainer();
- container.add(objects);
- return container;
+ void executeTask() {
+ new TaskContainer(this).execute();
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
index bc50ede3ea2..d1772e1497c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
@@ -27,6 +27,8 @@ import org.sonar.api.task.Task;
import org.sonar.api.task.TaskDefinition;
import org.sonar.api.task.TaskExtension;
import org.sonar.api.utils.SonarException;
+import org.sonar.batch.scan.ScanTask;
+import org.sonar.batch.tasks.ListTask;
import org.sonar.batch.tasks.Tasks;
public class TaskContainer extends ComponentContainer {
@@ -37,30 +39,20 @@ public class TaskContainer extends ComponentContainer {
@Override
protected void doBeforeStart() {
+ installCoreTasks();
installTaskExtensions();
installComponentsUsingTaskExtensions();
}
- public void execute() {
- startComponents();
-
- // default value is declared in CorePlugin
- String taskKey = get(Settings.class).getString(CoreProperties.TASK);
-
- TaskDefinition def = get(Tasks.class).definition(taskKey);
- if (def == null) {
- throw new SonarException("Task " + taskKey + " does not exist.");
- }
- Task task = get(def.taskClass());
- if (task != null) {
- task.execute();
- } else {
- throw new IllegalStateException("Task " + taskKey + " is badly defined.");
- }
+ private void installCoreTasks() {
+ add(
+ ScanTask.DEFINITION, ScanTask.class,
+ ListTask.DEFINITION, ListTask.class
+ );
}
private void installTaskExtensions() {
- get(ExtensionInstaller.class).install(this, new ExtensionInstaller.ComponentFilter() {
+ getComponentByType(ExtensionInstaller.class).install(this, new ExtensionInstaller.ComponentFilter() {
public boolean accept(Object extension) {
return ExtensionUtils.isType(extension, TaskExtension.class);
}
@@ -70,4 +62,21 @@ public class TaskContainer extends ComponentContainer {
private void installComponentsUsingTaskExtensions() {
add(ResourceTypes.class, MetricProvider.class, Tasks.class);
}
+
+ @Override
+ public void doAfterStart() {
+ // default value is declared in CorePlugin
+ String taskKey = getComponentByType(Settings.class).getString(CoreProperties.TASK);
+
+ TaskDefinition def = getComponentByType(Tasks.class).definition(taskKey);
+ if (def == null) {
+ throw new SonarException("Task " + taskKey + " does not exist");
+ }
+ Task task = getComponentByType(def.taskClass());
+ if (task != null) {
+ task.execute();
+ } else {
+ throw new IllegalStateException("Task " + taskKey + " is badly defined");
+ }
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
index fd2ed69ac6c..d7459b0e7a7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
@@ -21,14 +21,9 @@ package org.sonar.batch.bootstrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import org.slf4j.LoggerFactory;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.batch.bootstrap.BootstrapContainer;
import org.sonar.batch.bootstrap.BootstrapProperties;
-import org.sonar.batch.bootstrap.TaskContainer;
-import org.sonar.batch.scan.ScanTask;
-import org.sonar.batch.tasks.ListTask;
-import org.sonar.core.PicoUtils;
import java.util.Collections;
import java.util.List;
@@ -81,37 +76,14 @@ public final class Batch {
}
private void startBatch() {
- BootstrapContainer bootstrapContainer = null;
- try {
- List all = Lists.newArrayList(components);
- all.add(new BootstrapProperties(bootstrapProperties));
- if (projectReactor != null) {
- all.add(projectReactor);
- }
-
- bootstrapContainer = BootstrapContainer.create(all);
- bootstrapContainer.startComponents();
-
- TaskContainer taskContainer = new TaskContainer(bootstrapContainer);
- taskContainer.add(
- ScanTask.DEFINITION, ScanTask.class,
- ListTask.DEFINITION, ListTask.class
- );
-
- taskContainer.execute();
-
- } catch (RuntimeException e) {
- PicoUtils.propagateStartupException(e);
- } finally {
- try {
- if (bootstrapContainer != null) {
- bootstrapContainer.stopComponents();
- }
- } catch (Exception e) {
- // never throw exceptions in a finally block
- LoggerFactory.getLogger(Batch.class).error("Error while stopping batch", e);
- }
+ List all = Lists.newArrayList(components);
+ all.add(new BootstrapProperties(bootstrapProperties));
+ if (projectReactor != null) {
+ all.add(projectReactor);
}
+
+ BootstrapContainer bootstrapContainer = BootstrapContainer.create(all);
+ bootstrapContainer.execute();
}
public static Builder builder() {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
index b85b7e75bb4..0e001d1c3b7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
@@ -71,54 +71,54 @@ public class ModuleScanContainer extends ComponentContainer {
}
private void addCoreComponents() {
- ProjectDefinition moduleDefinition = get(ProjectTree.class).getProjectDefinition(module);
+ ProjectDefinition moduleDefinition = getComponentByType(ProjectTree.class).getProjectDefinition(module);
add(
- moduleDefinition,
- module.getConfiguration(),
- module,
- ModuleSettings.class);
+ moduleDefinition,
+ module.getConfiguration(),
+ module,
+ ModuleSettings.class);
// hack to initialize commons-configuration before ExtensionProviders
- get(ModuleSettings.class);
+ getComponentByType(ModuleSettings.class);
add(
- EventBus.class,
- Phases.class,
- PhasesTimeProfiler.class,
- UnsupportedProperties.class,
- Phases.getPhaseClasses(),
- moduleDefinition.getContainerExtensions(),
-
- // TODO move outside project, but not possible yet because of dependency of project settings (cf plsql)
- Languages.class,
-
- // file system
- PathResolver.class,
- FileExclusions.class,
- LanguageFilters.class,
- ExclusionFilters.class,
- DefaultProjectClasspath.class,
- new ModuleFileSystemProvider(),
- DeprecatedFileSystemAdapter.class,
- FileSystemLogger.class,
-
- // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
- get(ResourcePersister.class).getSnapshot(module),
-
- TimeMachineConfiguration.class,
- org.sonar.api.database.daos.MeasuresDao.class,
- DefaultSensorContext.class,
- BatchExtensionDictionnary.class,
- DefaultTimeMachine.class,
- ViolationFilters.class,
- ResourceFilters.class,
- DefaultProfileLoader.class,
- DryRunExporter.class,
- new ProfileProvider());
+ EventBus.class,
+ Phases.class,
+ PhasesTimeProfiler.class,
+ UnsupportedProperties.class,
+ Phases.getPhaseClasses(),
+ moduleDefinition.getContainerExtensions(),
+
+ // TODO move outside project, but not possible yet because of dependency of project settings (cf plsql)
+ Languages.class,
+
+ // file system
+ PathResolver.class,
+ FileExclusions.class,
+ LanguageFilters.class,
+ ExclusionFilters.class,
+ DefaultProjectClasspath.class,
+ new ModuleFileSystemProvider(),
+ DeprecatedFileSystemAdapter.class,
+ FileSystemLogger.class,
+
+ // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
+ getComponentByType(ResourcePersister.class).getSnapshot(module),
+
+ TimeMachineConfiguration.class,
+ org.sonar.api.database.daos.MeasuresDao.class,
+ DefaultSensorContext.class,
+ BatchExtensionDictionnary.class,
+ DefaultTimeMachine.class,
+ ViolationFilters.class,
+ ResourceFilters.class,
+ DefaultProfileLoader.class,
+ DryRunExporter.class,
+ new ProfileProvider());
}
private void addExtensions() {
- ExtensionInstaller installer = get(ExtensionInstaller.class);
+ ExtensionInstaller installer = getComponentByType(ExtensionInstaller.class);
installer.install(this, new ExtensionInstaller.ComponentFilter() {
public boolean accept(Object extension) {
if (ExtensionUtils.isType(extension, BatchExtension.class) && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_PROJECT)) {
@@ -134,14 +134,13 @@ public class ModuleScanContainer extends ComponentContainer {
@Override
protected void doAfterStart() {
- DefaultIndex index = get(DefaultIndex.class);
+ DefaultIndex index = getComponentByType(DefaultIndex.class);
index.setCurrentProject(module,
- get(ResourceFilters.class),
- get(ViolationFilters.class),
- get(RulesProfile.class));
+ getComponentByType(ResourceFilters.class),
+ getComponentByType(ViolationFilters.class),
+ getComponentByType(RulesProfile.class));
- get(Phases.class).execute(module);
+ getComponentByType(Phases.class).execute(module);
}
-
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index 74eaedaab4a..f57bbb2e085 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -63,52 +63,52 @@ public class ProjectScanContainer extends ComponentContainer {
private void addBatchComponents() {
add(
- DefaultResourceCreationLock.class,
- DefaultPersistenceManager.class,
- DependencyPersister.class,
- EventPersister.class,
- LinkPersister.class,
- MeasurePersister.class,
- MemoryOptimizer.class,
- DefaultResourcePermissions.class,
- DefaultResourcePersister.class,
- SourcePersister.class,
- DefaultNotificationManager.class,
- MetricProvider.class,
- ProjectExclusions.class,
- ProjectReactorReady.class,
- ProjectTree.class,
- ProjectConfigurator.class,
- DefaultIndex.class,
- DefaultFileLinesContextFactory.class,
- ProjectLock.class,
- LastSnapshots.class,
- ScanGraph.create(),
- TestPlanBuilder.class,
- TestableBuilder.class,
- ScanPerspectives.class,
- ScanGraphStore.class
+ DefaultResourceCreationLock.class,
+ DefaultPersistenceManager.class,
+ DependencyPersister.class,
+ EventPersister.class,
+ LinkPersister.class,
+ MeasurePersister.class,
+ MemoryOptimizer.class,
+ DefaultResourcePermissions.class,
+ DefaultResourcePersister.class,
+ SourcePersister.class,
+ DefaultNotificationManager.class,
+ MetricProvider.class,
+ ProjectExclusions.class,
+ ProjectReactorReady.class,
+ ProjectTree.class,
+ ProjectConfigurator.class,
+ DefaultIndex.class,
+ DefaultFileLinesContextFactory.class,
+ ProjectLock.class,
+ LastSnapshots.class,
+ ScanGraph.create(),
+ TestPlanBuilder.class,
+ TestableBuilder.class,
+ ScanPerspectives.class,
+ ScanGraphStore.class
);
}
private void fixMavenExecutor() {
- if (get(MavenPluginExecutor.class) == null) {
+ if (getComponentByType(MavenPluginExecutor.class) == null) {
add(FakeMavenPluginExecutor.class);
}
}
private void addBatchExtensions() {
- get(ExtensionInstaller.class).install(this, new ExtensionInstaller.ComponentFilter() {
+ getComponentByType(ExtensionInstaller.class).install(this, new ExtensionInstaller.ComponentFilter() {
public boolean accept(Object extension) {
return ExtensionUtils.isType(extension, BatchExtension.class)
- && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH);
+ && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH);
}
});
}
@Override
protected void doAfterStart() {
- ProjectTree tree = get(ProjectTree.class);
+ ProjectTree tree = getComponentByType(ProjectTree.class);
scanRecursively(tree.getRootProject());
}
@@ -120,13 +120,7 @@ public class ProjectScanContainer extends ComponentContainer {
}
private void scan(Project module) {
- ModuleScanContainer moduleContainer = new ModuleScanContainer(this, module);
- try {
- moduleContainer.startComponents();
- } finally {
- moduleContainer.stopComponents();
- removeChild();
- }
+ new ModuleScanContainer(this, module).execute();
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java
index f573be1d0fa..db3a4d21bfe 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java
@@ -33,7 +33,9 @@ import java.util.Collections;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
public class BootstrapContainerTest {
@@ -42,8 +44,8 @@ public class BootstrapContainerTest {
BootstrapContainer container = BootstrapContainer.create(Collections.emptyList());
container.doBeforeStart();
- assertThat(container.get(Logback.class)).isNotNull();
- assertThat(container.get(TempDirectories.class)).isNotNull();
+ assertThat(container.getComponentByType(Logback.class)).isNotNull();
+ assertThat(container.getComponentByType(TempDirectories.class)).isNotNull();
}
@Test
@@ -51,8 +53,8 @@ public class BootstrapContainerTest {
BootstrapContainer container = BootstrapContainer.create(Lists.newArrayList(Foo.class, new Bar()));
container.doBeforeStart();
- assertThat(container.get(Foo.class)).isNotNull();
- assertThat(container.get(Bar.class)).isNotNull();
+ assertThat(container.getComponentByType(Foo.class)).isNotNull();
+ assertThat(container.getComponentByType(Bar.class)).isNotNull();
}
@Test
@@ -64,7 +66,8 @@ public class BootstrapContainerTest {
metadata, plugin
));
- BootstrapContainer container = BootstrapContainer.create(Lists.newArrayList(pluginRepository));
+ BootstrapContainer container = spy(BootstrapContainer.create(Lists.newArrayList(pluginRepository)));
+ doNothing().when(container).executeTask();
container.doAfterStart();
assertThat(container.getComponentsByType(Plugin.class)).containsOnly(plugin);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java
index 23e2a311bf4..c7fbaa32855 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java
@@ -47,11 +47,11 @@ public class ExtensionInstallerTest {
Map<PluginMetadata, Plugin> newPlugin(final Object... extensions) {
Map<PluginMetadata, Plugin> result = Maps.newHashMap();
result.put(metadata,
- new SonarPlugin() {
- public List<?> getExtensions() {
- return Arrays.asList(extensions);
- }
+ new SonarPlugin() {
+ public List<?> getExtensions() {
+ return Arrays.asList(extensions);
}
+ }
);
return result;
}
@@ -64,8 +64,8 @@ public class ExtensionInstallerTest {
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings());
installer.install(container, new FooMatcher());
- assertThat(container.get(Foo.class)).isNotNull();
- assertThat(container.get(Bar.class)).isNull();
+ assertThat(container.getComponentByType(Foo.class)).isNotNull();
+ assertThat(container.getComponentByType(Bar.class)).isNull();
}
@Test
@@ -77,8 +77,8 @@ public class ExtensionInstallerTest {
installer.install(container, new FooMatcher());
- assertThat(container.get(Foo.class)).isNotNull();
- assertThat(container.get(Bar.class)).isNull();
+ assertThat(container.getComponentByType(Foo.class)).isNotNull();
+ assertThat(container.getComponentByType(Bar.class)).isNull();
}
@Test
@@ -90,8 +90,8 @@ public class ExtensionInstallerTest {
installer.install(container, new TrueMatcher());
- assertThat(container.get(Foo.class)).isNotNull();
- assertThat(container.get(Bar.class)).isNotNull();
+ assertThat(container.getComponentByType(Foo.class)).isNotNull();
+ assertThat(container.getComponentByType(Bar.class)).isNotNull();
}
@Test
@@ -104,10 +104,10 @@ public class ExtensionInstallerTest {
installer.install(container, new TrueMatcher());
- assertThat(container.get(MavenExtension.class)).isNull();
- assertThat(container.get(AntExtension.class)).isNotNull();
- assertThat(container.get(Foo.class)).isNotNull();
- assertThat(container.get(Bar.class)).isNotNull();
+ assertThat(container.getComponentByType(MavenExtension.class)).isNull();
+ assertThat(container.getComponentByType(AntExtension.class)).isNotNull();
+ assertThat(container.getComponentByType(Foo.class)).isNotNull();
+ assertThat(container.getComponentByType(Bar.class)).isNotNull();
}
private static class FooMatcher implements ExtensionInstaller.ComponentFilter {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java
index ee15a324f9f..dd4b5719cd5 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java
@@ -27,12 +27,15 @@ import org.picocontainer.MutablePicoContainer;
import org.picocontainer.behaviors.OptInCaching;
import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
import org.picocontainer.monitors.NullComponentMonitor;
+import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.ServerComponent;
import org.sonar.api.config.PropertyDefinitions;
import javax.annotation.Nullable;
+import java.util.List;
+
/**
* @since 2.12
*/
@@ -65,21 +68,42 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
addSingleton(this);
}
+ public void execute() {
+ boolean threw = true;
+ try {
+ startComponents();
+ threw = false;
+ } finally {
+ stopComponents(threw);
+ }
+ }
+
/**
* This method MUST NOT be renamed start() because the container is registered itself in picocontainer. Starting
* a component twice is not authorized.
*/
- public final ComponentContainer startComponents() {
- doBeforeStart();
- pico.start();
- doAfterStart();
- return this;
+ public ComponentContainer startComponents() {
+ try {
+ doBeforeStart();
+ pico.start();
+ doAfterStart();
+ return this;
+ } catch (Exception e) {
+ throw PicoUtils.propagate(e);
+ }
}
+ /**
+ * This method aims to be overridden
+ */
+
protected void doBeforeStart() {
}
+ /**
+ * This method aims to be overridden
+ */
protected void doAfterStart() {
}
@@ -88,15 +112,29 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
* This method MUST NOT be renamed stop() because the container is registered itself in picocontainer. Starting
* a component twice is not authorized.
*/
- public final ComponentContainer stopComponents() {
- pico.stop();
+ public ComponentContainer stopComponents() {
+ return stopComponents(false);
+ }
+
+ public ComponentContainer stopComponents(boolean swallowException) {
+ try {
+ pico.stop();
+ if (parent != null) {
+ parent.removeChild();
+ }
+ } catch (RuntimeException e) {
+ if (!swallowException) {
+ throw PicoUtils.propagate(e);
+ }
+ LoggerFactory.getLogger(getClass()).error("Fail to stop container", e);
+ }
return this;
}
/**
* @since 3.5
*/
- public final ComponentContainer add(Object... objects) {
+ public ComponentContainer add(Object... objects) {
for (Object object : objects) {
if (object instanceof ComponentAdapter) {
addPicoAdapter((ComponentAdapter) object);
@@ -109,7 +147,7 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
return this;
}
- public final ComponentContainer addSingleton(Object component) {
+ public ComponentContainer addSingleton(Object component) {
return addComponent(component, true);
}
@@ -117,44 +155,40 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
* @param singleton return always the same instance if true, else a new instance
* is returned each time the component is requested
*/
- public final ComponentContainer addComponent(Object component, boolean singleton) {
+ public ComponentContainer addComponent(Object component, boolean singleton) {
pico.as(singleton ? Characteristics.CACHE : Characteristics.NO_CACHE).addComponent(getComponentKey(component), component);
declareExtension(null, component);
return this;
}
- public final ComponentContainer addExtension(@Nullable PluginMetadata plugin, Object extension) {
+ public ComponentContainer addExtension(@Nullable PluginMetadata plugin, Object extension) {
pico.as(Characteristics.CACHE).addComponent(getComponentKey(extension), extension);
declareExtension(plugin, extension);
return this;
}
- public final void declareExtension(@Nullable PluginMetadata plugin, Object extension) {
+ public void declareExtension(@Nullable PluginMetadata plugin, Object extension) {
propertyDefinitions.addComponent(extension, plugin != null ? plugin.getName() : "");
}
- public final ComponentContainer addPicoAdapter(ComponentAdapter adapter) {
+ public ComponentContainer addPicoAdapter(ComponentAdapter adapter) {
pico.addAdapter(adapter);
return this;
}
- public <T> T get(Class<T> key) {
- return pico.getComponent(key);
- }
-
- public final <T> T getComponentByType(Class<T> tClass) {
+ public <T> T getComponentByType(Class<T> tClass) {
return pico.getComponent(tClass);
}
- public final Object getComponentByKey(Object key) {
+ public Object getComponentByKey(Object key) {
return pico.getComponent(key);
}
- public final <T> java.util.List<T> getComponentsByType(java.lang.Class<T> tClass) {
+ public <T> List<T> getComponentsByType(Class<T> tClass) {
return pico.getComponents(tClass);
}
- public final ComponentContainer removeChild() {
+ public ComponentContainer removeChild() {
if (child != null) {
pico.removeChildContainer(child.pico);
child = null;
@@ -162,7 +196,7 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
return this;
}
- public final ComponentContainer createChild() {
+ public ComponentContainer createChild() {
return new ComponentContainer(this);
}
diff --git a/sonar-core/src/main/java/org/sonar/core/PicoUtils.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/PicoUtils.java
index 8a5599b1431..7f7c9544d7c 100644
--- a/sonar-core/src/main/java/org/sonar/core/PicoUtils.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/PicoUtils.java
@@ -17,17 +17,17 @@
* License along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
-package org.sonar.core;
+package org.sonar.api.platform;
import com.google.common.base.Throwables;
import org.picocontainer.PicoLifecycleException;
-public final class PicoUtils {
+class PicoUtils {
private PicoUtils() {
}
- public static Throwable sanitize(Throwable t) {
+ static Throwable sanitize(Throwable t) {
Throwable result = t;
Throwable cause = t.getCause();
if (t instanceof PicoLifecycleException && cause != null) {
@@ -36,12 +36,11 @@ public final class PicoUtils {
} else {
result = cause;
}
-
}
return result;
}
- public static void propagateStartupException(Throwable t) {
+ static RuntimeException propagate(Throwable t) {
throw Throwables.propagate(sanitize(t));
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java
index f880578a923..6722b6e550c 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java
@@ -19,13 +19,15 @@
*/
package org.sonar.api.platform;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.picocontainer.Startable;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.Property;
import org.sonar.api.config.PropertyDefinitions;
import java.util.Arrays;
-import java.util.List;
import static junit.framework.Assert.assertTrue;
import static org.fest.assertions.Assertions.assertThat;
@@ -35,6 +37,9 @@ import static org.mockito.Mockito.verify;
public class ComponentContainerTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
@Test
public void shouldRegisterItself() {
ComponentContainer container = new ComponentContainer();
@@ -134,29 +139,72 @@ public class ComponentContainerTest {
PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
assertThat(propertyDefinitions.get("foo")).isNotNull();
assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull();
+ assertThat(container.getComponentByKey(ComponentWithProperty.class)).isNotNull();
}
@Test
public void test_add_class() {
ComponentContainer container = new ComponentContainer();
container.add(ComponentWithProperty.class, SimpleComponent.class);
- assertThat(container.get(ComponentWithProperty.class)).isNotNull();
- assertThat(container.get(SimpleComponent.class)).isNotNull();
+ assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull();
+ assertThat(container.getComponentByType(SimpleComponent.class)).isNotNull();
}
@Test
public void test_add_collection() {
ComponentContainer container = new ComponentContainer();
container.add(Arrays.asList(ComponentWithProperty.class, SimpleComponent.class));
- assertThat(container.get(ComponentWithProperty.class)).isNotNull();
- assertThat(container.get(SimpleComponent.class)).isNotNull();
+ assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull();
+ assertThat(container.getComponentByType(SimpleComponent.class)).isNotNull();
}
@Test
public void test_add_adapter() {
ComponentContainer container = new ComponentContainer();
container.add(new SimpleComponentProvider());
- assertThat(container.get(SimpleComponent.class)).isNotNull();
+ assertThat(container.getComponentByType(SimpleComponent.class)).isNotNull();
+ }
+
+ @Test
+ public void should_fail_to_start_execution() {
+ ComponentContainer container = new ComponentContainer();
+ container.add(UnstartableComponent.class);
+
+ // do not expect a PicoException
+ thrown.expect(IllegalStateException.class);
+ container.startComponents();
+ }
+
+ @Test
+ public void stop_exception_should_not_hide_start_exception() {
+ ComponentContainer container = new ComponentContainer();
+ container.add(UnstartableComponent.class, UnstoppableComponent.class);
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Fail to start");
+ container.execute();
+ }
+
+ @Test
+ public void should_fail_to_stop_execution() {
+ ComponentContainer container = new ComponentContainer();
+ container.add(UnstoppableComponent.class);
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Fail to stop");
+ container.execute();
+ }
+
+ @Test
+ public void should_execute_components() {
+ ComponentContainer container = new ComponentContainer();
+ Startable component = mock(Startable.class);
+ container.add(component);
+
+ container.execute();
+
+ verify(component).start();
+ verify(component).stop();
}
public static class StartableComponent {
@@ -171,6 +219,25 @@ public class ComponentContainerTest {
}
}
+ public static class UnstartableComponent {
+ public void start() {
+ throw new IllegalStateException("Fail to start");
+ }
+
+ public void stop() {
+
+ }
+ }
+
+ public static class UnstoppableComponent {
+ public void start() {
+ }
+
+ public void stop() {
+ throw new IllegalStateException("Fail to stop");
+ }
+ }
+
@Property(key = "foo", defaultValue = "bar", name = "Foo")
public static class ComponentWithProperty {
diff --git a/sonar-core/src/test/java/org/sonar/core/PicoUtilsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/platform/PicoUtilsTest.java
index 336a3706963..672608fd21b 100644
--- a/sonar-core/src/test/java/org/sonar/core/PicoUtilsTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/platform/PicoUtilsTest.java
@@ -17,73 +17,74 @@
* License along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
-package org.sonar.core;
+package org.sonar.api.platform;
-import org.hamcrest.core.Is;
import org.junit.Test;
+import org.picocontainer.Characteristics;
+import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoLifecycleException;
-import org.sonar.api.platform.ComponentContainer;
import java.io.IOException;
-import static org.junit.Assert.assertThat;
+import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.fail;
+
public class PicoUtilsTest {
@Test
public void shouldSanitizePicoLifecycleException() {
Throwable th = PicoUtils.sanitize(newPicoLifecycleException(false));
- assertThat(th, Is.is(IllegalStateException.class));
- assertThat(th.getMessage(), Is.is("A good reason to fail"));
+ assertThat(th).isInstanceOf(IllegalStateException.class);
+ assertThat(th.getMessage()).isEqualTo("A good reason to fail");
}
@Test
public void shouldSanitizePicoLifecycleException_no_wrapper_message() {
Throwable th = PicoUtils.sanitize(new PicoLifecycleException(null, null, new IllegalStateException("msg")));
- assertThat(th, Is.is(IllegalStateException.class));
- assertThat(th.getMessage(), Is.is("msg"));
+ assertThat(th).isInstanceOf(IllegalStateException.class);
+ assertThat(th.getMessage()).isEqualTo("msg");
}
@Test
public void shouldNotSanitizeOtherExceptions() {
Throwable th = PicoUtils.sanitize(new IllegalArgumentException("foo"));
- assertThat(th, Is.is(IllegalArgumentException.class));
- assertThat(th.getMessage(), Is.is("foo"));
+ assertThat(th).isInstanceOf(IllegalArgumentException.class);
+ assertThat(th.getMessage()).isEqualTo("foo");
}
@Test
public void shouldPropagateInitialUncheckedException() {
try {
- PicoUtils.propagateStartupException(newPicoLifecycleException(false));
+ PicoUtils.propagate(newPicoLifecycleException(false));
fail();
} catch (RuntimeException e) {
- assertThat(e, Is.is(IllegalStateException.class));
+ assertThat(e).isInstanceOf(IllegalStateException.class);
}
}
@Test
public void shouldThrowUncheckedExceptionWhenPropagatingCheckedException() {
try {
- PicoUtils.propagateStartupException(newPicoLifecycleException(true));
+ PicoUtils.propagate(newPicoLifecycleException(true));
fail();
} catch (RuntimeException e) {
- assertThat(e.getCause(), Is.is(IOException.class));
- assertThat(e.getCause().getMessage(), Is.is("Checked"));
+ assertThat(e.getCause()).isInstanceOf(IOException.class);
+ assertThat(e.getCause().getMessage()).isEqualTo("Checked");
}
}
private PicoLifecycleException newPicoLifecycleException(boolean initialCheckedException) {
- ComponentContainer componentContainer = new ComponentContainer();
+ MutablePicoContainer container = ComponentContainer.createPicoContainer().as(Characteristics.CACHE);
if (initialCheckedException) {
- componentContainer.addSingleton(CheckedFailureComponent.class);
+ container.addComponent(CheckedFailureComponent.class);
} else {
- componentContainer.addSingleton(UncheckedFailureComponent.class);
+ container.addComponent(UncheckedFailureComponent.class);
}
try {
- componentContainer.startComponents();
+ container.start();
return null;
} catch (PicoLifecycleException e) {
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index aa73d07d316..b9ac8c908d7 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -35,7 +35,6 @@ import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.api.utils.UriReader;
import org.sonar.api.workflow.internal.DefaultWorkflow;
-import org.sonar.core.PicoUtils;
import org.sonar.core.component.SnapshotPerspectives;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.GwtI18n;
@@ -141,9 +140,8 @@ public final class Platform {
} catch (RuntimeException e) {
// full stacktrace is lost by jruby. It must be logged now.
- Throwable initialException = PicoUtils.sanitize(e);
- LoggerFactory.getLogger(getClass()).error(initialException.getMessage(), initialException);
- PicoUtils.propagateStartupException(initialException);
+ LoggerFactory.getLogger(getClass()).error(e.getMessage(), e);
+ throw e;
}
}
}
@@ -159,9 +157,8 @@ public final class Platform {
profiler.stop();
} catch (RuntimeException e) {
// full stacktrace is lost by jruby. It must be logged now.
- Throwable initialException = PicoUtils.sanitize(e);
- LoggerFactory.getLogger(getClass()).error(initialException.getMessage(), initialException);
- PicoUtils.propagateStartupException(initialException);
+ LoggerFactory.getLogger(getClass()).error(e.getMessage(), e);
+ throw e;
}
}
}