From ef5bf7fdece84e5a52c8d478c8a733ecdf4d57f1 Mon Sep 17 00:00:00 2001 From: simonbrandhof Date: Wed, 5 Oct 2011 00:44:37 +0200 Subject: [PATCH] SONAR-2861 New Configuration API The component org.apache.commons.Configuration is still available but plugins should use org.sonar.api.config.Settings. It also implies the following issues : SONAR-2870 do not rebuild the WAR file when editing sonar.properties SONAR-2869 allow to use the annotations @Properties/@Property on extensions --- .../checkstyle/CheckstyleConfiguration.java | 17 +- .../checkstyle/CheckstyleConstants.java | 2 - .../CheckstyleConfigurationTest.java | 8 +- .../org/sonar/plugins/core/CorePlugin.java | 33 ++- .../src/main/assembly/war/build.xml | 27 +- .../src/main/java/org/sonar/batch/Batch.java | 10 +- .../org/sonar/batch/ProjectConfigurator.java | 98 +++---- .../java/org/sonar/batch/ProjectTree.java | 19 +- .../java/org/sonar/batch/ServerMetadata.java | 18 +- .../bootstrap/BatchExtensionInstaller.java | 65 +++-- .../sonar/batch/bootstrap/BatchModule.java | 62 ++--- .../bootstrap/BatchPluginRepository.java | 22 +- .../batch/bootstrap/BootstrapModule.java | 67 ++--- .../org/sonar/batch/bootstrap/DryRun.java | 11 +- .../org/sonar/batch/bootstrap/Module.java | 67 ++--- .../bootstrap/ProjectExtensionInstaller.java | 2 +- .../sonar/batch/bootstrap/ProjectModule.java | 80 +++--- .../org/sonar/batch/config/BatchSettings.java | 60 +++++ .../batch/config/BatchSettingsEnhancer.java | 58 ++++ .../DeprecatedConfigurationProvider.java | 22 +- .../sonar/batch/config/ProjectSettings.java | 86 ++++++ .../sonar/batch/DecoratorsSelectorTest.java | 8 +- .../sonar/batch/ProjectConfiguratorTest.java | 87 +++--- .../java/org/sonar/batch/ProjectTreeTest.java | 4 - .../org/sonar/batch/ServerMetadataTest.java | 20 +- .../BatchExtensionInstallerTest.java | 47 ++-- .../bootstrap/BatchPluginRepositoryTest.java | 47 ++-- .../org/sonar/batch/bootstrap/DryRunTest.java | 18 +- .../org/sonar/batch/bootstrap/ModuleTest.java | 23 +- .../ProjectExtensionInstallerTest.java | 10 +- .../sonar/core/config/ConfigurationUtils.java | 125 +++++++++ .../core/plugins/PluginClassloaders.java | 1 - .../session/AbstractDatabaseConnector.java | 41 +-- .../jpa/session/DriverDatabaseConnector.java | 18 +- .../jpa/session/MemoryDatabaseConnector.java | 9 +- .../core/config/ConfigurationUtilsTest.java | 73 +++++ .../plugin/AbstractPluginRepositoryTest.java | 1 - .../AbstractDatabaseConnectorTest.java | 7 +- .../session/DriverDatabaseConnectorTest.java | 6 +- .../main/java/org/sonar/maven/SonarMojo.java | 2 +- .../main/java/org/sonar/maven3/SonarMojo.java | 11 +- .../api/batch/BatchExtensionDictionnary.java | 26 +- .../sonar/api/config/PropertyDefinitions.java | 114 ++++++++ .../java/org/sonar/api/config/Settings.java | 251 ++++++++++++++++++ .../api/platform/ComponentContainer.java | 164 ++++++++++++ .../org/sonar/api/resources/Languages.java | 3 +- .../java/org/sonar/api/resources/Project.java | 2 + .../org/sonar/api/utils/HttpDownloader.java | 60 ++--- .../org/sonar/api/utils/IocContainer.java | 6 + .../batch/BatchExtensionDictionnaryTest.java | 23 +- .../api/config/PropertyDefinitionsTest.java | 93 +++++++ .../org/sonar/api/config/SettingsTest.java | 124 +++++++++ .../api/platform/ComponentContainerTest.java | 147 ++++++++++ .../sonar/api/utils/HttpDownloaderTest.java | 19 +- .../org/sonar/api/utils/IocContainerTest.java | 39 --- .../sonar/server/charts/ChartsServlet.java | 2 +- .../configuration/ConfigurationFactory.java | 86 ------ .../configuration/ConfigurationLogger.java | 52 ---- .../configuration/CoreConfiguration.java | 44 --- .../server/configuration/ServerSettings.java | 156 +++++++++++ .../server/database/EmbeddedDatabase.java | 32 +-- .../database/EmbeddedDatabaseFactory.java | 14 +- .../database/JndiDatabaseConnector.java | 15 +- .../server/mavendeployer/MavenRepository.java | 12 +- .../notifications/NotificationService.java | 48 ++-- .../platform/DefaultServerFileSystem.java | 10 +- .../org/sonar/server/platform/Platform.java | 199 +++++++------- .../platform/PlatformLifecycleListener.java | 6 +- .../DefaultServerPluginRepository.java | 61 +---- .../plugins/ServerExtensionInstaller.java | 101 +++++++ .../plugins/StaticResourcesServlet.java | 2 +- .../server/plugins/UpdateCenterClient.java | 29 +- .../sonar/server/startup/GwtPublisher.java | 12 +- .../sonar/server/ui/AuthenticatorFactory.java | 12 +- .../server/ui/DatabaseSessionFilter.java | 2 +- .../java/org/sonar/server/ui/JRubyFacade.java | 120 +++++---- .../src/main/resources/sonar-war.properties | 9 + .../app/controllers/project_controller.rb | 15 +- .../app/controllers/settings_controller.rb | 12 +- .../controllers/updatecenter_controller.rb | 4 +- .../app/controllers/users_controller.rb | 2 +- .../WEB-INF/app/helpers/application_helper.rb | 2 +- .../main/webapp/WEB-INF/app/models/server.rb | 2 +- .../app/views/layouts/_layout.html.erb | 4 +- .../webapp/WEB-INF/lib/database_version.rb | 6 +- .../webapp/WEB-INF/lib/need_authentication.rb | 10 +- .../ConfigurationFactoryTest.java | 51 ---- .../server/database/EmbeddedDatabaseTest.java | 4 +- .../database/JndiDatabaseConnectorTest.java | 6 +- .../NotificationServiceTest.java | 33 +-- .../DefaultServerPluginRepositoryTest.java | 43 +-- .../plugins/ServerExtensionInstallerTest.java | 102 +++++++ .../server/ui/AuthenticatorFactoryTest.java | 30 +-- 93 files changed, 2549 insertions(+), 1264 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/config/BatchSettings.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/config/BatchSettingsEnhancer.java rename sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationException.java => sonar-batch/src/main/java/org/sonar/batch/config/DeprecatedConfigurationProvider.java (62%) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java create mode 100644 sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java create mode 100644 sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java delete mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/utils/IocContainerTest.java delete mode 100644 sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationFactory.java delete mode 100644 sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationLogger.java delete mode 100644 sonar-server/src/main/java/org/sonar/server/configuration/CoreConfiguration.java create mode 100644 sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java create mode 100644 sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java create mode 100644 sonar-server/src/main/resources/sonar-war.properties delete mode 100644 sonar-server/src/test/java/org/sonar/server/configuration/ConfigurationFactoryTest.java create mode 100644 sonar-server/src/test/java/org/sonar/server/plugins/ServerExtensionInstallerTest.java diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConfiguration.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConfiguration.java index 7461fe4cc60..de9d5d5ce7a 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConfiguration.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConfiguration.java @@ -23,13 +23,14 @@ import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import com.puppycrawl.tools.checkstyle.DefaultConfiguration; import com.puppycrawl.tools.checkstyle.PropertiesExpander; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; -import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.CharEncoding; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.BatchExtension; import org.sonar.api.CoreProperties; +import org.sonar.api.Property; +import org.sonar.api.config.Settings; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Java; import org.sonar.api.resources.ProjectFileSystem; @@ -41,16 +42,22 @@ import java.util.List; import java.util.Locale; import java.util.Properties; +@org.sonar.api.Properties({ + @Property(key = CheckstyleConfiguration.PROPERTY_GENERATE_XML, + defaultValue = "false", + name = "Generate XML Report", + project = false, global = false)}) public class CheckstyleConfiguration implements BatchExtension { private static final Logger LOG = LoggerFactory.getLogger(CheckstyleConfiguration.class); + public static final String PROPERTY_GENERATE_XML = "sonar.checkstyle.generateXml"; private CheckstyleProfileExporter confExporter; private RulesProfile profile; - private Configuration conf; + private Settings conf; private ProjectFileSystem fileSystem; - public CheckstyleConfiguration(Configuration conf, CheckstyleProfileExporter confExporter, RulesProfile profile, ProjectFileSystem fileSystem) { + public CheckstyleConfiguration(Settings conf, CheckstyleProfileExporter confExporter, RulesProfile profile, ProjectFileSystem fileSystem) { this.conf = conf; this.confExporter = confExporter; this.profile = profile; @@ -79,7 +86,7 @@ public class CheckstyleConfiguration implements BatchExtension { } public File getTargetXMLReport() { - if (conf.getBoolean(CheckstyleConstants.GENERATE_XML_KEY, CheckstyleConstants.GENERATE_XML_DEFAULT_VALUE)) { + if (conf.getBoolean(PROPERTY_GENERATE_XML)) { return new File(fileSystem.getSonarWorkingDirectory(), "checkstyle-result.xml"); } return null; @@ -112,7 +119,7 @@ public class CheckstyleConfiguration implements BatchExtension { } public Locale getLocale() { - return new Locale(conf.getString(CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY, CoreProperties.CORE_VIOLATION_LOCALE_DEFAULT_VALUE)); + return new Locale(conf.getString(CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY)); } public Charset getCharset() { diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConstants.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConstants.java index e110efcba84..5299f047598 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConstants.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleConstants.java @@ -30,8 +30,6 @@ public final class CheckstyleConstants { public static final String FILTERS_KEY = "sonar.checkstyle.filters"; public static final String FILTERS_DEFAULT_VALUE = ""; - public static final String GENERATE_XML_KEY = "sonar.checkstyle.generateXml"; - public static final boolean GENERATE_XML_DEFAULT_VALUE = false; private CheckstyleConstants() { } diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleConfigurationTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleConfigurationTest.java index dac37703a98..e14bac06bb8 100644 --- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleConfigurationTest.java +++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleConfigurationTest.java @@ -19,9 +19,9 @@ */ package org.sonar.plugins.checkstyle; -import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.io.FileUtils; import org.junit.Test; +import org.sonar.api.config.Settings; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Project; import org.sonar.api.test.MavenTestUtils; @@ -48,12 +48,6 @@ public class CheckstyleConfigurationTest { assertThat(FileUtils.readFileToString(xmlFile), is("")); } - @Test - public void shouldGetDefaultLocaleForMessages() { - CheckstyleConfiguration configuration = new CheckstyleConfiguration(new PropertiesConfiguration(), null, null, null); - assertThat(configuration.getLocale(), is(Locale.ENGLISH)); - } - public class FakeExporter extends CheckstyleProfileExporter { @Override public void exportProfile(RulesProfile profile, Writer writer) { diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 354e00c9e37..75f70be23f0 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -176,7 +176,38 @@ import java.util.List; project = true, global = false, defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_5, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS) + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), + + + // SERVER-SIDE TECHNICAL PROPERTIES + + @Property( + key = "sonar.useStructureDump", + name = "Use Structure Dump", + description = "Used when creating database schema", + project = false, + global = false, + defaultValue = "true"), + @Property( + key = "sonar.authenticator.downcase", + name = "Downcase login", + description = "Downcase login during user authentication, typically for Active Directory", + project = false, + global = false, + defaultValue = "false"), + @Property( + key = CoreProperties.CORE_AUTHENTICATOR_CREATE_USERS, + name = "Create user accounts", + description = "Create accounts when authenticating users via an external system", + project = false, + global = false, + defaultValue = "false"), + @Property( + key = CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, + name = "Ignore failures during authenticator startup", + defaultValue = "false", + project = false, + global = false) }) public class CorePlugin extends SonarPlugin { diff --git a/sonar-application/src/main/assembly/war/build.xml b/sonar-application/src/main/assembly/war/build.xml index b8409fbaa64..0832a7a58ff 100644 --- a/sonar-application/src/main/assembly/war/build.xml +++ b/sonar-application/src/main/assembly/war/build.xml @@ -32,17 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - - - - - - - - - - + @@ -75,10 +65,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 * supported web servers are Jetty and Tomcat 5.x/6.x/7.x * the web application uses the Sonar home directory. For this reason it must be deployed on this host only. * the war file must be rebuilt when : - - configuration is updated (files in the directory conf/) - - the Sonar home directory is moved to other location - - sonar is upgraded to a new version - It does not have to be rebuilt when a plugin is removed or installed. + - logback configuration is updated (conf/logback.xml) + - the Sonar home directory is moved to other location + - sonar is upgraded to a new version ----------------------------------------------------------------------------------------------------------- @@ -87,12 +76,4 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - - - Setting home to: ${sonarHome} - - sonar.home=${sonarHome} - - - \ No newline at end of file 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 2461b865064..70c92d06097 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/Batch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/Batch.java @@ -30,11 +30,11 @@ public final class Batch { private Module bootstrapModule; /** - * @deprecated since 2.9. Replaced by the factory method. + * @deprecated since 2.9. Replaced by the factory method. Use by Ant Task 1.1 */ @Deprecated public Batch(Configuration configuration, Object... bootstrapperComponents) { - this.bootstrapModule = new BootstrapModule(extractProjectReactor(bootstrapperComponents), configuration, bootstrapperComponents).init(); + this.bootstrapModule = new BootstrapModule(extractProjectReactor(bootstrapperComponents), bootstrapperComponents).init(); } static ProjectReactor extractProjectReactor(Object[] components) { @@ -54,12 +54,12 @@ public final class Batch { return deprecatedReactor.toProjectReactor(); } - private Batch(ProjectReactor reactor, Configuration configuration, Object... bootstrapperComponents) { - this.bootstrapModule = new BootstrapModule(reactor, configuration, bootstrapperComponents).init(); + private Batch(ProjectReactor reactor, Object... bootstrapperComponents) { + this.bootstrapModule = new BootstrapModule(reactor, bootstrapperComponents).init(); } public static Batch create(ProjectReactor projectReactor, Configuration configuration, Object... bootstrapperComponents) { - return new Batch(projectReactor, configuration, bootstrapperComponents); + return new Batch(projectReactor, bootstrapperComponents); } /** diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java b/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java index 6659aa5618f..ed9db7d9e05 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java @@ -19,38 +19,38 @@ */ package org.sonar.batch; -import org.apache.commons.configuration.*; +import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.time.DateUtils; import org.apache.maven.project.MavenProject; +import org.sonar.api.BatchComponent; import org.sonar.api.CoreProperties; import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.ResourceModel; import org.sonar.api.database.model.Snapshot; import org.sonar.api.resources.Java; import org.sonar.api.resources.Project; -import org.sonar.api.utils.SonarException; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; -public class ProjectConfigurator { +public class ProjectConfigurator implements BatchComponent { private DatabaseSession databaseSession; + private Settings settings; - public ProjectConfigurator(DatabaseSession databaseSession) { + public ProjectConfigurator(DatabaseSession databaseSession, Settings settings) { this.databaseSession = databaseSession; + this.settings = settings; } public Project create(ProjectDefinition definition) { - Configuration configuration = getStartupConfiguration(definition); - Project project = new Project(definition.getKey(), loadProjectBranch(configuration), definition.getName()) - .setDescription(StringUtils.defaultString(definition.getDescription(), "")) - .setPackaging("jar"); + Project project = new Project(definition.getKey(), loadProjectBranch(), definition.getName()); + // For backward compatibility we must set POM and actual packaging + project.setDescription(StringUtils.defaultString(definition.getDescription())); + project.setPackaging("jar"); + for (Object component : definition.getContainerExtensions()) { if (component instanceof MavenProject) { MavenProject pom = (MavenProject) component; @@ -61,39 +61,25 @@ public class ProjectConfigurator { return project; } - Configuration getStartupConfiguration(ProjectDefinition project) { - CompositeConfiguration configuration = new CompositeConfiguration(); - configuration.addConfiguration(new SystemConfiguration()); - configuration.addConfiguration(new EnvironmentConfiguration()); - configuration.addConfiguration(new MapConfiguration(project.getProperties())); - return configuration; - } - - String loadProjectBranch(Configuration configuration) { - return configuration.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); - } - - public void configure(Project project, ProjectDefinition def) { - ProjectConfiguration projectConfiguration = new ProjectConfiguration(databaseSession, def); - configure(project, projectConfiguration); + String loadProjectBranch() { + return settings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); } - void configure(Project project, Configuration projectConfiguration) { - Date analysisDate = loadAnalysisDate(projectConfiguration); - project.setConfiguration(projectConfiguration) - .setExclusionPatterns(loadExclusionPatterns(projectConfiguration)) + public ProjectConfigurator configure(Project project) { + Date analysisDate = loadAnalysisDate(); + project + .setConfiguration(new PropertiesConfiguration()) // will be populated by ProjectSettings + .setExclusionPatterns(loadExclusionPatterns()) .setAnalysisDate(analysisDate) .setLatestAnalysis(isLatestAnalysis(project.getKey(), analysisDate)) - .setAnalysisVersion(loadAnalysisVersion(projectConfiguration)) - .setAnalysisType(loadAnalysisType(projectConfiguration)) - .setLanguageKey(loadLanguageKey(projectConfiguration)); + .setAnalysisVersion(loadAnalysisVersion()) + .setAnalysisType(loadAnalysisType()) + .setLanguageKey(loadLanguageKey()); + return this; } - static String[] loadExclusionPatterns(Configuration configuration) { - String[] exclusionPatterns = configuration.getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY); - if (exclusionPatterns == null) { - exclusionPatterns = new String[0]; - } + String[] loadExclusionPatterns() { + String[] exclusionPatterns = settings.getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY); for (int i = 0; i < exclusionPatterns.length; i++) { exclusionPatterns[i] = StringUtils.trim(exclusionPatterns[i]); } @@ -109,28 +95,18 @@ public class ProjectConfigurator { return true; } - Date loadAnalysisDate(Configuration configuration) { - String formattedDate = configuration.getString(CoreProperties.PROJECT_DATE_PROPERTY); - if (formattedDate == null) { - return new Date(); - } - - DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - try { - // see SONAR-908 make sure that a time is defined for the date. - Date date = DateUtils.setHours(format.parse(formattedDate), 0); - return DateUtils.setMinutes(date, 1); - - } catch (ParseException e) { - throw new SonarException("The property " + CoreProperties.PROJECT_DATE_PROPERTY - + " does not respect the format yyyy-MM-dd (for example 2008-05-23) : " + formattedDate, e); + Date loadAnalysisDate() { + Date date = settings.getDate(CoreProperties.PROJECT_DATE_PROPERTY); + if (date == null) { + date = new Date(); } + return date; } - Project.AnalysisType loadAnalysisType(Configuration configuration) { - String value = configuration.getString(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY); + Project.AnalysisType loadAnalysisType() { + String value = settings.getString(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY); if (value == null) { - return (configuration.getBoolean("sonar.light", false) ? Project.AnalysisType.STATIC : Project.AnalysisType.DYNAMIC); + return ("true".equals(settings.getString("sonar.light")) ? Project.AnalysisType.STATIC : Project.AnalysisType.DYNAMIC); } if ("true".equals(value)) { return Project.AnalysisType.DYNAMIC; @@ -141,11 +117,11 @@ public class ProjectConfigurator { return Project.AnalysisType.STATIC; } - String loadAnalysisVersion(Configuration configuration) { - return configuration.getString(CoreProperties.PROJECT_VERSION_PROPERTY); + String loadAnalysisVersion() { + return settings.getString(CoreProperties.PROJECT_VERSION_PROPERTY); } - String loadLanguageKey(Configuration configuration) { - return configuration.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY, Java.KEY); + String loadLanguageKey() { + return StringUtils.defaultIfBlank(settings.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY), Java.KEY); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java b/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java index 10548b7169e..7d9524ca93b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java @@ -21,13 +21,13 @@ package org.sonar.batch; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.LoggerFactory; import org.sonar.api.batch.bootstrap.ProjectBuilder; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.api.database.DatabaseSession; import org.sonar.api.resources.Project; import java.io.IOException; @@ -42,14 +42,15 @@ public class ProjectTree { private Map projectsByDef; public ProjectTree(ProjectReactor projectReactor, //NOSONAR the unused parameter 'builders' is used for the startup order of components - DatabaseSession databaseSession, + ProjectConfigurator projectConfigurator, /* Must be executed after ProjectBuilders */ ProjectBuilder[] builders) { - this(projectReactor, databaseSession); + this(projectReactor, projectConfigurator); } - public ProjectTree(ProjectReactor projectReactor, DatabaseSession databaseSession) { - configurator = new ProjectConfigurator(databaseSession); + public ProjectTree(ProjectReactor projectReactor, //NOSONAR the unused parameter 'builders' is used for the startup order of components + ProjectConfigurator projectConfigurator) { this.projectReactor = projectReactor; + this.configurator = projectConfigurator; } ProjectTree(ProjectConfigurator configurator) { @@ -79,8 +80,8 @@ public class ProjectTree { } // Configure - for (Map.Entry entry : projectsByDef.entrySet()) { - configurator.configure(entry.getValue(), entry.getKey()); + for (Project project : projects) { + configurator.configure(project); } applyExclusions(); @@ -91,8 +92,8 @@ public class ProjectTree { String[] excludedArtifactIds = project.getConfiguration().getStringArray("sonar.skippedModules"); String[] includedArtifactIds = project.getConfiguration().getStringArray("sonar.includedModules"); - Set includedModulesIdSet = new HashSet(); - Set excludedModulesIdSet = new HashSet(); + Set includedModulesIdSet = Sets.newHashSet(); + Set excludedModulesIdSet = Sets.newHashSet(); if (includedArtifactIds != null) { includedModulesIdSet.addAll(Arrays.asList(includedArtifactIds)); diff --git a/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java index 97dae9df62f..fcd0951dd52 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java @@ -19,10 +19,10 @@ */ package org.sonar.batch; -import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; import java.text.ParseException; @@ -31,22 +31,22 @@ import java.util.Date; public class ServerMetadata extends Server { - private Configuration conf; + private Settings settings; - public ServerMetadata(Configuration conf) { - this.conf = conf; + public ServerMetadata(Settings settings) { + this.settings = settings; } public String getId() { - return conf.getString(CoreProperties.SERVER_ID); + return settings.getString(CoreProperties.SERVER_ID); } public String getVersion() { - return conf.getString(CoreProperties.SERVER_VERSION); + return settings.getString(CoreProperties.SERVER_VERSION); } public Date getStartedAt() { - String dateString = conf.getString(CoreProperties.SERVER_STARTTIME); + String dateString = settings.getString(CoreProperties.SERVER_STARTTIME); if (dateString != null) { try { return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateString); @@ -59,11 +59,11 @@ public class ServerMetadata extends Server { } public String getURL() { - return StringUtils.removeEnd(conf.getString("sonar.host.url", "http://localhost:9000"), "/"); + return StringUtils.removeEnd(StringUtils.defaultIfBlank(settings.getString("sonar.host.url"), "http://localhost:9000"), "/"); } @Override public String getPermanentServerId() { - return conf.getString(CoreProperties.PERMANENT_SERVER_ID); + return settings.getString(CoreProperties.PERMANENT_SERVER_ID); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionInstaller.java index 75dec73bac8..4a690ac1a45 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionInstaller.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionInstaller.java @@ -19,16 +19,20 @@ */ package org.sonar.batch.bootstrap; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; import org.sonar.api.BatchComponent; +import org.sonar.api.Extension; import org.sonar.api.ExtensionProvider; import org.sonar.api.Plugin; import org.sonar.api.batch.CoverageExtension; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.measures.Metric; import org.sonar.api.measures.Metrics; +import org.sonar.api.platform.PluginMetadata; import org.sonar.batch.bootstrapper.EnvironmentInformation; -import java.util.List; +import java.util.Map; public final class BatchExtensionInstaller implements BatchComponent { @@ -43,40 +47,63 @@ public final class BatchExtensionInstaller implements BatchComponent { } public void install(Module module) { - for (Plugin plugin : pluginRepository.getPlugins()) { + ListMultimap installedExtensionsByPlugin = ArrayListMultimap.create(); + for (Map.Entry entry : pluginRepository.getPluginsByMetadata().entrySet()) { + PluginMetadata metadata = entry.getKey(); + Plugin plugin = entry.getValue(); + + module.addExtension(metadata, plugin); + for (Object extension : plugin.getExtensions()) { - installExtension(module, extension); + if (installExtension(module, metadata, extension)) { + installedExtensionsByPlugin.put(metadata, extension); + } else { + module.declareExtension(metadata, extension); + } + } + } + for (Map.Entry entry : installedExtensionsByPlugin.entries()) { + PluginMetadata plugin = entry.getKey(); + Object extension = entry.getValue(); + if (isExtensionProvider(extension)) { + ExtensionProvider provider = (ExtensionProvider) module.getComponentByKey(extension); + installProvider(module, plugin, provider); } } - installExtensionProviders(module); installMetrics(module); } + static boolean isExtensionProvider(Object extension) { + return isType(extension, ExtensionProvider.class) || extension instanceof ExtensionProvider; + } + + static boolean isType(Object extension, Class extensionClass) { + Class clazz = (extension instanceof Class ? (Class) extension : extension.getClass()); + return extensionClass.isAssignableFrom(clazz); + } + private void installMetrics(Module module) { for (Metrics metrics : module.getComponents(Metrics.class)) { for (Metric metric : metrics.getMetrics()) { - module.addComponent(metric.getKey(), metric); + module.addCoreSingleton(metric); } } } - void installExtensionProviders(Module module) { - List providers = module.getComponents(ExtensionProvider.class); - for (ExtensionProvider provider : providers) { - Object obj = provider.provide(); - if (obj != null) { - if (obj instanceof Iterable) { - for (Object extension : (Iterable) obj) { - installExtension(module, extension); - } - } else { - installExtension(module, obj); + private void installProvider(Module module, PluginMetadata plugin, ExtensionProvider provider) { + Object obj = provider.provide(); + if (obj != null) { + if (obj instanceof Iterable) { + for (Object ext : (Iterable) obj) { + installExtension(module, plugin, ext); } + } else { + installExtension(module, plugin, obj); } } } - void installExtension(Module module, Object extension) { + boolean installExtension(Module module, PluginMetadata plugin, Object extension) { if (ExtensionUtils.isBatchExtension(extension) && ExtensionUtils.isSupportedEnvironment(extension, environment) && ExtensionUtils.checkDryRun(extension, dryRun.isEnabled()) && @@ -84,7 +111,9 @@ public final class BatchExtensionInstaller implements BatchComponent { if (ExtensionUtils.isType(extension, CoverageExtension.class)) { throw new IllegalArgumentException("Instantiation strategy " + InstantiationStrategy.PER_BATCH + " is not supported on CoverageExtension components: " + extension); } - module.addComponent(extension); + module.addExtension(plugin, extension); + return true; } + return false; } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java index 3134c5ec39f..822d6ca7a8d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java @@ -25,7 +25,7 @@ import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; import org.sonar.api.utils.ServerHttpClient; import org.sonar.batch.DefaultResourceCreationLock; -import org.sonar.batch.ProjectConfiguration; +import org.sonar.batch.ProjectConfigurator; import org.sonar.batch.ProjectTree; import org.sonar.batch.components.*; import org.sonar.batch.index.*; @@ -48,55 +48,55 @@ public class BatchModule extends Module { @Override protected void configure() { - addComponent(ProjectConfiguration.class); - addComponent(ProjectTree.class); - addComponent(DefaultResourceCreationLock.class); - addComponent(DefaultIndex.class); + addCoreSingleton(ProjectTree.class); + addCoreSingleton(ProjectConfigurator.class); + addCoreSingleton(DefaultResourceCreationLock.class); + addCoreSingleton(DefaultIndex.class); if (dryRun) { - addComponent(ReadOnlyPersistenceManager.class); + addCoreSingleton(ReadOnlyPersistenceManager.class); } else { - addComponent(DefaultPersistenceManager.class); - addComponent(DependencyPersister.class); - addComponent(EventPersister.class); - addComponent(LinkPersister.class); - addComponent(MeasurePersister.class); - addComponent(MemoryOptimizer.class); - addComponent(DefaultResourcePersister.class); - addComponent(SourcePersister.class); + addCoreSingleton(DefaultPersistenceManager.class); + addCoreSingleton(DependencyPersister.class); + addCoreSingleton(EventPersister.class); + addCoreSingleton(LinkPersister.class); + addCoreSingleton(MeasurePersister.class); + addCoreSingleton(MemoryOptimizer.class); + addCoreSingleton(DefaultResourcePersister.class); + addCoreSingleton(SourcePersister.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); - addComponent(DefaultNotificationManager.class); - addComponent(DefaultUserFinder.class); + addCoreSingleton(Plugins.class); + addCoreSingleton(ServerHttpClient.class); + addCoreSingleton(MeasuresDao.class); + addCoreSingleton(CacheRuleFinder.class); + addCoreSingleton(CacheMetricFinder.class); + addCoreSingleton(PastSnapshotFinderByDate.class); + addCoreSingleton(PastSnapshotFinderByDays.class); + addCoreSingleton(PastSnapshotFinderByPreviousAnalysis.class); + addCoreSingleton(PastSnapshotFinderByVersion.class); + addCoreSingleton(PastMeasuresLoader.class); + addCoreSingleton(PastSnapshotFinder.class); + addCoreSingleton(DefaultNotificationManager.class); + addCoreSingleton(DefaultUserFinder.class); addCoreMetrics(); addBatchExtensions(); } private void addBatchExtensions() { - BatchExtensionInstaller installer = getComponent(BatchExtensionInstaller.class); + BatchExtensionInstaller installer = getComponentByType(BatchExtensionInstaller.class); installer.install(this); } void addCoreMetrics() { for (Metric metric : CoreMetrics.getMetrics()) { - addComponent(metric.getKey(), metric); + addCoreSingleton(metric); } } @Override protected void doStart() { - ProjectTree projectTree = getComponent(ProjectTree.class); + ProjectTree projectTree = getComponentByType(ProjectTree.class); analyze(projectTree.getRootProject()); } @@ -110,7 +110,7 @@ public class BatchModule extends Module { projectComponents.start(); } finally { projectComponents.stop(); - uninstallChild(projectComponents); + uninstallChild(); } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java index 249c94b79b7..27061aadc67 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java @@ -22,7 +22,6 @@ package org.sonar.batch.bootstrap; import com.google.common.base.Joiner; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +29,7 @@ import org.sonar.api.CoreProperties; import org.sonar.api.Plugin; import org.sonar.api.Properties; import org.sonar.api.Property; +import org.sonar.api.config.Settings; import org.sonar.api.platform.PluginMetadata; import org.sonar.api.platform.PluginRepository; import org.sonar.core.plugins.PluginClassloaders; @@ -51,14 +51,14 @@ public class BatchPluginRepository implements PluginRepository { private Set blackList = null; private PluginClassloaders classLoaders; - public BatchPluginRepository(ArtifactDownloader artifactDownloader, Configuration configuration) { + public BatchPluginRepository(ArtifactDownloader artifactDownloader, Settings settings) { this.artifactDownloader = artifactDownloader; - if (configuration.getString(CoreProperties.BATCH_INCLUDE_PLUGINS) != null) { - whiteList = Sets.newTreeSet(Arrays.asList(configuration.getStringArray(CoreProperties.BATCH_INCLUDE_PLUGINS))); + if (settings.hasKey(CoreProperties.BATCH_INCLUDE_PLUGINS)) { + whiteList = Sets.newTreeSet(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_INCLUDE_PLUGINS))); LOG.info("Include plugins: " + Joiner.on(", ").join(whiteList)); } - if (configuration.getString(CoreProperties.BATCH_EXCLUDE_PLUGINS) != null) { - blackList = Sets.newTreeSet(Arrays.asList(configuration.getStringArray(CoreProperties.BATCH_EXCLUDE_PLUGINS))); + if (settings.hasKey(CoreProperties.BATCH_EXCLUDE_PLUGINS)) { + blackList = Sets.newTreeSet(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_EXCLUDE_PLUGINS))); LOG.info("Exclude plugins: " + Joiner.on(", ").join(blackList)); } // TODO reactivate somewhere else: LOG.info("Execution environment: {} {}", environment.getKey(), environment.getVersion()); @@ -133,4 +133,14 @@ public class BatchPluginRepository implements PluginRepository { } return blackList == null || !blackList.contains(pluginKey); } + + public Map getPluginsByMetadata() { + Map result = Maps.newHashMap(); + for (Map.Entry entry : metadataByKey.entrySet()) { + String pluginKey = entry.getKey(); + PluginMetadata metadata = entry.getValue(); + result.put(metadata, pluginsByKey.get(pluginKey)); + } + return result; + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java index 2c925b71674..ce6985b8c2e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java @@ -19,13 +19,15 @@ */ package org.sonar.batch.bootstrap; -import org.apache.commons.configuration.Configuration; -import org.sonar.api.Plugin; +import org.apache.commons.configuration.PropertiesConfiguration; import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.config.Settings; import org.sonar.api.utils.HttpDownloader; import org.sonar.batch.FakeMavenPluginExecutor; import org.sonar.batch.MavenPluginExecutor; import org.sonar.batch.ServerMetadata; +import org.sonar.batch.config.BatchSettings; +import org.sonar.batch.config.BatchSettingsEnhancer; import org.sonar.jpa.session.DatabaseSessionProvider; import org.sonar.jpa.session.DriverDatabaseConnector; import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory; @@ -37,52 +39,52 @@ import java.net.URLClassLoader; */ public class BootstrapModule extends Module { - private Configuration configuration; private Object[] boostrapperComponents; private ProjectReactor reactor; - public BootstrapModule(ProjectReactor reactor, Configuration configuration, Object... boostrapperComponents) { + public BootstrapModule(ProjectReactor reactor, Object... boostrapperComponents) { this.reactor = reactor; - this.configuration = configuration; this.boostrapperComponents = boostrapperComponents; } @Override protected void configure() { - addComponent(reactor); - addComponent(configuration);// this configuration does not access database - addComponent(DryRun.class); - 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(ArtifactDownloader.class);// registered here because used by BootstrapClassLoader - addComponent(JdbcDriverHolder.class); + addCoreSingleton(reactor); + addCoreSingleton(new PropertiesConfiguration()); + addCoreSingleton(BatchSettings.class); + addCoreSingleton(DryRun.class); + addCoreSingleton(ServerMetadata.class);// registered here because used by BootstrapClassLoader + addCoreSingleton(TempDirectories.class);// registered here because used by BootstrapClassLoader + addCoreSingleton(HttpDownloader.class);// registered here because used by BootstrapClassLoader + addCoreSingleton(ArtifactDownloader.class);// registered here because used by BootstrapClassLoader + addCoreSingleton(JdbcDriverHolder.class); - URLClassLoader bootstrapClassLoader = getComponent(JdbcDriverHolder.class).getClassLoader(); + URLClassLoader bootstrapClassLoader = getComponentByType(JdbcDriverHolder.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); + addCoreSingleton(new DriverDatabaseConnector(getComponentByType(Settings.class), bootstrapClassLoader)); + addCoreSingleton(ThreadLocalDatabaseSessionFactory.class); addAdapter(new DatabaseSessionProvider()); for (Object component : boostrapperComponents) { - addComponent(component); + addCoreSingleton(component); } if (!isMavenPluginExecutorRegistered()) { - addComponent(FakeMavenPluginExecutor.class); + addCoreSingleton(FakeMavenPluginExecutor.class); } - // LIMITATION : list of plugins to download is currently loaded from database. It should be loaded from - // remote HTTP index. - addComponent(BatchPluginRepository.class); - addComponent(BatchExtensionInstaller.class); - addComponent(ProjectExtensionInstaller.class); + addCoreSingleton(BatchPluginRepository.class); + addCoreSingleton(BatchExtensionInstaller.class); + addCoreSingleton(ProjectExtensionInstaller.class); + addCoreSingleton(BatchSettingsEnhancer.class); } boolean isMavenPluginExecutorRegistered() { - for (Object component : boostrapperComponents) { - if (component instanceof Class && MavenPluginExecutor.class.isAssignableFrom((Class) component)) { - return true; + if (boostrapperComponents != null) { + for (Object component : boostrapperComponents) { + if (component instanceof Class && MavenPluginExecutor.class.isAssignableFrom((Class) component)) { + return true; + } } } return false; @@ -90,19 +92,8 @@ public class BootstrapModule extends Module { @Override protected void doStart() { - addPlugins(); - boolean dryRun = getComponent(DryRun.class).isEnabled(); + boolean dryRun = getComponentByType(DryRun.class).isEnabled(); Module batchComponents = installChild(new BatchModule(dryRun)); batchComponents.start(); } - - private void addPlugins() { - // Plugins have been loaded during the startup of BatchPluginRepository. - // In a perfect world BatchPluginRepository should be a factory which injects new components into container, but - // (it seems that) this feature does not exist in PicoContainer. - // Limitation: the methods start() and stop() are not called on org.sonar.api.Plugin instances. - for (Plugin plugin : getComponent(BatchPluginRepository.class).getPlugins()) { - addComponent(plugin); - } - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DryRun.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DryRun.java index c269fc6b126..c3a96ab63de 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DryRun.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DryRun.java @@ -19,14 +19,17 @@ */ package org.sonar.batch.bootstrap; -import org.apache.commons.configuration.Configuration; +import org.sonar.api.BatchComponent; +import org.sonar.api.Property; +import org.sonar.api.config.Settings; import org.sonar.api.utils.Logs; -public class DryRun { +@Property(key="sonar.dryRun", defaultValue = "false", name="Dry Run") +public class DryRun implements BatchComponent { private boolean enabled; - public DryRun(Configuration conf) { - enabled = conf.getBoolean("sonar.dryRun", Boolean.FALSE); + public DryRun(Settings settings) { + enabled = settings.getBoolean("sonar.dryRun"); if (enabled) { Logs.INFO.info("Dry run"); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java index df9991e89a5..bba921ab6de 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java @@ -19,10 +19,9 @@ */ package org.sonar.batch.bootstrap; -import org.picocontainer.Characteristics; import org.picocontainer.ComponentAdapter; -import org.picocontainer.MutablePicoContainer; -import org.sonar.api.utils.IocContainer; +import org.sonar.api.platform.ComponentContainer; +import org.sonar.api.platform.PluginMetadata; import java.util.List; @@ -33,20 +32,19 @@ import java.util.List; */ public abstract class Module { - private MutablePicoContainer container; - + ComponentContainer container; /** * @return this */ public final Module init() { - return init(IocContainer.buildPicoContainer()); + return init(new ComponentContainer()); } /** * @return this */ - private Module init(MutablePicoContainer container) { + private Module init(ComponentContainer container) { this.container = container; configure(); return this; @@ -68,24 +66,23 @@ public abstract class Module { * @return installed module */ public final Module installChild(Module child) { - MutablePicoContainer childContainer = container.makeChildContainer(); + ComponentContainer childContainer = container.createChild(); // 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 - childContainer.addComponent(new IocContainer(childContainer)); - childContainer.setName(child.toString()); + //childContainer.addComponent(new IocContainer(childContainer)); child.init(childContainer); return child; } - public final void uninstallChild(Module child) { - container.removeChildContainer(child.container); + public final void uninstallChild() { + container.removeChild(); } /** * @return this */ public final Module start() { - container.start(); + container.startComponents(); doStart(); return this; } @@ -100,7 +97,7 @@ public abstract class Module { public final Module stop() { try { doStop(); - container.stop(); + container.stopComponents(); } catch (Exception e) { // ignore } @@ -113,39 +110,43 @@ public abstract class Module { /** * 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)}. + * {@link #addCoreSingleton(Object)}, {@link #addComponent(Object, Object)} or {@link #addAdapter(ComponentAdapter)}. */ protected abstract void configure(); - protected final void addComponent(Object component) { - if (component instanceof Class) { - container.as(Characteristics.CACHE).addComponent(component); - } else { - container.as(Characteristics.CACHE).addComponent(component.getClass().getCanonicalName() + "-" + component.toString(), component); - } + protected final void addCoreSingleton(Object component) { + container.addSingleton(component); } - protected final void addComponent(Object componentKey, Object component) { - container.as(Characteristics.CACHE).addComponent(componentKey, component); + protected final void declareExtension(PluginMetadata plugin, Object extension) { + container.declareExtension(plugin, extension); + } + + protected final void addExtension(PluginMetadata plugin, Object extension) { + container.addExtension(plugin, extension); } protected final void addAdapter(ComponentAdapter componentAdapter) { - container.addAdapter(componentAdapter); + container.addPicoAdapter(componentAdapter); } - public final T getComponent(Class componentType) { - return container.getComponent(componentType); + public final T getComponentByType(Class componentType) { + return container.getComponentByType(componentType); } - public final List getComponents(Class componentType) { - return container.getComponents(componentType); + public final Object getComponentByKey(Object key) { + return container.getComponentByKey(key); } - /** - * TODO should not be used and should be removed - */ - public final MutablePicoContainer getContainer() { - return container; + public final List getComponents(Class componentType) { + return container.getComponentsByType(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/bootstrap/ProjectExtensionInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExtensionInstaller.java index 0ec164f7ca4..145d971387e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExtensionInstaller.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExtensionInstaller.java @@ -77,7 +77,7 @@ public final class ProjectExtensionInstaller implements BatchComponent { ExtensionUtils.checkDryRun(extension, dryRun.isEnabled()) && !isDeactivatedCoverageExtension(extension, project, pluginKey) && !isMavenExtensionOnEmulatedMavenProject(extension, project)) { - module.addComponent(extension); + module.addCoreSingleton(extension); return extension; } return null; diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java index c54b8d6d126..5381fc093ed 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java @@ -29,16 +29,21 @@ import org.sonar.api.resources.Languages; import org.sonar.api.resources.Project; import org.sonar.api.resources.ProjectFileSystem; import org.sonar.api.rules.DefaultRulesManager; +import org.sonar.api.utils.IocContainer; import org.sonar.api.utils.SonarException; import org.sonar.batch.*; import org.sonar.batch.components.TimeMachineConfiguration; +import org.sonar.batch.config.DeprecatedConfigurationProvider; +import org.sonar.batch.config.ProjectSettings; import org.sonar.batch.events.EventBus; import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.DefaultResourcePersister; import org.sonar.batch.phases.Phases; import org.sonar.batch.phases.PhasesTimeProfiler; import org.sonar.core.components.DefaultModelFinder; -import org.sonar.jpa.dao.*; +import org.sonar.jpa.dao.DaoFacade; +import org.sonar.jpa.dao.ProfilesDao; +import org.sonar.jpa.dao.RulesDao; import java.util.Arrays; @@ -62,49 +67,52 @@ public class ProjectModule extends Module { private void addProjectComponents() { - ProjectDefinition projectDefinition = getComponent(ProjectTree.class).getProjectDefinition(project); - addComponent(projectDefinition); + ProjectDefinition projectDefinition = getComponentByType(ProjectTree.class).getProjectDefinition(project); + addCoreSingleton(projectDefinition); + addCoreSingleton(project); + addCoreSingleton(project.getConfiguration()); + addCoreSingleton(ProjectSettings.class); + addAdapter(new DeprecatedConfigurationProvider()); + addCoreSingleton(IocContainer.class); + for (Object component : projectDefinition.getContainerExtensions()) { - addComponent(component); + addCoreSingleton(component); } - - addComponent(project); - addComponent(project.getConfiguration()); - addComponent(DefaultProjectClasspath.class); - addComponent(DefaultProjectFileSystem2.class); - addComponent(DaoFacade.class); - addComponent(RulesDao.class); + addCoreSingleton(DefaultProjectClasspath.class); + addCoreSingleton(DefaultProjectFileSystem2.class); + addCoreSingleton(DaoFacade.class); + addCoreSingleton(RulesDao.class); if (!dryRun) { // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor) - addComponent(getComponent(DefaultResourcePersister.class).getSnapshot(project)); + addCoreSingleton(getComponentByType(DefaultResourcePersister.class).getSnapshot(project)); } - addComponent(TimeMachineConfiguration.class); - addComponent(org.sonar.api.database.daos.MeasuresDao.class); - addComponent(ProfilesDao.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(ProfileLoader.class, DefaultProfileLoader.class); + addCoreSingleton(TimeMachineConfiguration.class); + addCoreSingleton(org.sonar.api.database.daos.MeasuresDao.class); + addCoreSingleton(ProfilesDao.class); + addCoreSingleton(DefaultRulesManager.class); + addCoreSingleton(DefaultSensorContext.class); + addCoreSingleton(Languages.class); + addCoreSingleton(BatchExtensionDictionnary.class); + addCoreSingleton(DefaultTimeMachine.class); + addCoreSingleton(ViolationFilters.class); + addCoreSingleton(ResourceFilters.class); + addCoreSingleton(DefaultModelFinder.class); + addCoreSingleton(DefaultProfileLoader.class); addAdapter(new ProfileProvider()); } private void addCoreComponents() { - addComponent(EventBus.class); - addComponent(Phases.class); - addComponent(PhasesTimeProfiler.class); + addCoreSingleton(EventBus.class); + addCoreSingleton(Phases.class); + addCoreSingleton(PhasesTimeProfiler.class); for (Class clazz : Phases.getPhaseClasses(dryRun)) { - addComponent(clazz); + addCoreSingleton(clazz); } } private void addProjectPluginExtensions() { - ProjectExtensionInstaller installer = getComponent(ProjectExtensionInstaller.class); + ProjectExtensionInstaller installer = getComponentByType(ProjectExtensionInstaller.class); installer.install(this, project); } @@ -124,22 +132,22 @@ public class ProjectModule extends Module { */ @Override protected void doStart() { - Language language = getComponent(Languages.class).get(project.getLanguageKey()); + Language language = getComponentByType(Languages.class).get(project.getLanguageKey()); if (language == null) { throw new SonarException("Language with key '" + project.getLanguageKey() + "' not found"); } project.setLanguage(language); - DefaultIndex index = getComponent(DefaultIndex.class); + DefaultIndex index = getComponentByType(DefaultIndex.class); index.setCurrentProject(project, - getComponent(ResourceFilters.class), - getComponent(ViolationFilters.class), - getComponent(RulesProfile.class)); + getComponentByType(ResourceFilters.class), + getComponentByType(ViolationFilters.class), + getComponentByType(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(getComponentByType(ProjectFileSystem.class)); - getComponent(Phases.class).execute(project); + getComponentByType(Phases.class).execute(project); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BatchSettings.java b/sonar-batch/src/main/java/org/sonar/batch/config/BatchSettings.java new file mode 100644 index 00000000000..9c86975cc77 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/config/BatchSettings.java @@ -0,0 +1,60 @@ +/* + * 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.config; + +import org.apache.commons.configuration.Configuration; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; +import org.sonar.core.config.ConfigurationUtils; + +import java.util.Map; + +/** + * @since 2.12 + */ +public final class BatchSettings extends Settings { + private Configuration deprecatedConfiguration; + private ProjectReactor reactor; + + public BatchSettings(PropertyDefinitions propertyDefinitions, ProjectReactor reactor, Configuration deprecatedConfiguration) { + super(propertyDefinitions); + this.reactor = reactor; + this.deprecatedConfiguration = deprecatedConfiguration; + load(); + } + + public BatchSettings load() { + clear(); + + // order is important -> bottom-up. The last one overrides all the others. + addProperties(reactor.getRoot().getProperties()); + addEnvironmentVariables(); + addSystemProperties(); + + updateDeprecatedCommonsConfiguration(); + + return this; + } + + public void updateDeprecatedCommonsConfiguration() { + ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedConfiguration); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BatchSettingsEnhancer.java b/sonar-batch/src/main/java/org/sonar/batch/config/BatchSettingsEnhancer.java new file mode 100644 index 00000000000..a770fa64adf --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/config/BatchSettingsEnhancer.java @@ -0,0 +1,58 @@ +/* + * 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.config; + +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.database.configuration.Property; +import org.sonar.core.config.ConfigurationUtils; +import org.sonar.jpa.session.DatabaseSessionFactory; + +import java.util.List; + +/** + * @since 2.12 + */ +public final class BatchSettingsEnhancer { + + private DatabaseSessionFactory dbFactory; + private BatchSettings settings; + private ProjectReactor reactor; + + public BatchSettingsEnhancer(DatabaseSessionFactory dbFactory, BatchSettings settings, ProjectReactor reactor) { + this.dbFactory = dbFactory; + this.settings = settings; + this.reactor = reactor; + } + + public void start() { + String projectKey = reactor.getRoot().getKey(); + setIfNotDefined(ConfigurationUtils.getProjectProperties(dbFactory, projectKey)); + setIfNotDefined(ConfigurationUtils.getGlobalProperties(dbFactory)); + settings.updateDeprecatedCommonsConfiguration(); + } + + private void setIfNotDefined(List dbProperties) { + for (Property dbProperty : dbProperties) { + if (!settings.hasKey(dbProperty.getKey())) { + settings.setProperty(dbProperty.getKey(), dbProperty.getValue()); + } + } + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationException.java b/sonar-batch/src/main/java/org/sonar/batch/config/DeprecatedConfigurationProvider.java similarity index 62% rename from sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationException.java rename to sonar-batch/src/main/java/org/sonar/batch/config/DeprecatedConfigurationProvider.java index 827f77cbc85..636a5adde25 100644 --- a/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationException.java +++ b/sonar-batch/src/main/java/org/sonar/batch/config/DeprecatedConfigurationProvider.java @@ -17,21 +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.server.configuration; +package org.sonar.batch.config; -public class ConfigurationException extends RuntimeException { - public ConfigurationException() { - } +import org.apache.commons.configuration.Configuration; +import org.picocontainer.injectors.ProviderAdapter; +import org.sonar.api.resources.Project; - public ConfigurationException(String s) { - super(s); - } +public class DeprecatedConfigurationProvider extends ProviderAdapter { - public ConfigurationException(String s, Throwable throwable) { - super(s, throwable); - } - - public ConfigurationException(Throwable throwable) { - super(throwable); + public Configuration provide(Project project, ProjectSettings settings) {//NOSONAR the parameter ProjectSettings is declared to be sure that it is initialized + // configuration is valid because it has been updated by ProjectSettings + return project.getConfiguration(); } } + diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java b/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java new file mode 100644 index 00000000000..4fcc837791b --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java @@ -0,0 +1,86 @@ +/* + * 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.config; + +import org.apache.commons.configuration.Configuration; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; +import org.sonar.api.database.configuration.Property; +import org.sonar.api.resources.Project; +import org.sonar.core.config.ConfigurationUtils; +import org.sonar.jpa.session.DatabaseSessionFactory; + +import java.util.List; + +/** + * @since 2.12 + */ +public class ProjectSettings extends Settings { + + private Configuration deprecatedCommonsConf; + private ProjectDefinition projectDefinition; + private DatabaseSessionFactory dbFactory; + + public ProjectSettings(PropertyDefinitions definitions, ProjectDefinition projectDefinition, DatabaseSessionFactory dbFactory, Project project) { + super(definitions); + this.deprecatedCommonsConf = project.getConfiguration(); // Configuration is not a parameter to be sure that the project conf is used, not the global one + this.projectDefinition = projectDefinition; + this.dbFactory = dbFactory; + load(); + } + + public ProjectSettings load() { + clear(); + + // order is important -> bottom-up. The last one overrides all the others. + loadDatabaseGlobalSettings(); + loadDatabaseProjectSettings(projectDefinition); + addProperties(projectDefinition.getProperties()); + addEnvironmentVariables(); + addSystemProperties(); + + updateDeprecatedCommonsConfiguration(); + + return this; + } + + private void loadDatabaseProjectSettings(ProjectDefinition projectDef) { + if (projectDef.getParent() != null) { + loadDatabaseProjectSettings(projectDef.getParent()); + } + List props = ConfigurationUtils.getProjectProperties(dbFactory, projectDef.getKey()); + for (Property dbProperty : props) { + setProperty(dbProperty.getKey(), dbProperty.getValue()); + } + } + + private void loadDatabaseGlobalSettings() { + List props = ConfigurationUtils.getGlobalProperties(dbFactory); + for (Property dbProperty : props) { + setProperty(dbProperty.getKey(), dbProperty.getValue()); + } + } + + private void updateDeprecatedCommonsConfiguration() { + ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedCommonsConf); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java b/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java index 2be1e1fc189..044038e17a8 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java @@ -21,12 +21,12 @@ package org.sonar.batch; import org.apache.commons.collections.CollectionUtils; import org.junit.Test; -import org.picocontainer.containers.TransientPicoContainer; import org.sonar.api.batch.BatchExtensionDictionnary; import org.sonar.api.batch.Decorator; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.DependedUpon; import org.sonar.api.measures.*; +import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; @@ -75,11 +75,9 @@ public class DecoratorsSelectorTest { } private BatchExtensionDictionnary newDictionnary(Object... extensions) { - TransientPicoContainer ioc = new TransientPicoContainer(); - int index = 0; + ComponentContainer ioc = new ComponentContainer(); for (Object extension : extensions) { - ioc.addComponent("" + index, extension); - index++; + ioc.addSingleton(extension); } return new BatchExtensionDictionnary(ioc); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/ProjectConfiguratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/ProjectConfiguratorTest.java index 48bdbe1f96d..4d2903e1e0a 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/ProjectConfiguratorTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/ProjectConfiguratorTest.java @@ -19,15 +19,9 @@ */ package org.sonar.batch; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.apache.commons.configuration.PropertiesConfiguration; -import org.junit.Before; import org.junit.Test; import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; import org.sonar.api.resources.Java; import org.sonar.api.resources.Project; import org.sonar.jpa.test.AbstractDbUnitTestCase; @@ -35,30 +29,27 @@ import org.sonar.jpa.test.AbstractDbUnitTestCase; import java.text.SimpleDateFormat; import java.util.Date; -public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { - - private ProjectConfigurator configurator = null; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; - @Before - public void before() { - configurator = new ProjectConfigurator(getSession()); - } +public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { @Test - public void noExclusionPatterns() { + public void testNoExclusionPatterns() { Project project = new Project("key"); - configurator.configure(project, new PropertiesConfiguration()); - + new ProjectConfigurator(getSession(), new Settings()).configure(project); assertThat(project.getExclusionPatterns().length, is(0)); } @Test - public void manyExclusionPatterns() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); - configuration.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*,foo,*/bar"); + public void testManyExclusionPatterns() { + Settings settings = new Settings(); + settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*,foo,*/bar"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), settings).configure(project); assertThat(project.getExclusionPatterns().length, is(3)); assertThat(project.getExclusionPatterns()[0], is("**/*")); @@ -73,11 +64,11 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { */ @Test public void trimExclusionPatterns() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, " foo "); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.getExclusionPatterns().length, is(1)); assertThat(project.getExclusionPatterns()[0], is("foo")); @@ -85,11 +76,11 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { @Test public void getLanguageFromConfiguration() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "foo"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.getLanguageKey(), is("foo")); } @@ -97,7 +88,7 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { @Test public void defaultLanguageIsJava() { Project project = new Project("key"); - configurator.configure(project, new PropertiesConfiguration()); + new ProjectConfigurator(getSession(), new Settings()).configure(project); assertThat(project.getLanguageKey(), is(Java.KEY)); } @@ -105,37 +96,35 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { @Test public void analysisIsTodayByDefault() { Project project = new Project("key"); - configurator.configure(project, new PropertiesConfiguration()); + new ProjectConfigurator(getSession(), new Settings()).configure(project); Date today = new Date(); assertTrue(today.getTime() - project.getAnalysisDate().getTime() < 1000); } @Test public void analysisDateCouldBeExplicitlySet() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); - configuration.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2005-01-30"); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2005-01-30"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), settings).configure(project); assertEquals("30012005", new SimpleDateFormat("ddMMyyyy").format(project.getAnalysisDate())); } @Test(expected = RuntimeException.class) public void failIfAnalyisDateIsNotValid() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2005/30/01"); Project project = new Project("key"); - configurator.configure(project, configuration); - - project.getAnalysisDate(); + new ProjectConfigurator(getSession(), configuration).configure(project); } @Test public void sonarLightIsDeprecated() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty("sonar.light", "true"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.getAnalysisType(), is(Project.AnalysisType.STATIC)); } @@ -143,34 +132,34 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { @Test public void defaultAnalysisTypeIsDynamic() { Project project = new Project("key"); - configurator.configure(project, new PropertiesConfiguration()); + new ProjectConfigurator(getSession(), new Settings()).configure(project); assertThat(project.getAnalysisType(), is(Project.AnalysisType.DYNAMIC)); } @Test public void explicitDynamicAnalysis() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY, "true"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.getAnalysisType(), is(Project.AnalysisType.DYNAMIC)); } @Test public void explicitStaticAnalysis() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY, "false"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.getAnalysisType(), is(Project.AnalysisType.STATIC)); } @Test public void explicitDynamicAnalysisReusingReports() { - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY, "reuseReports"); Project project = new Project("key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.getAnalysisType(), is(Project.AnalysisType.REUSE_REPORTS)); } @@ -190,11 +179,11 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { public void isLatestAnalysis() { setupData("isLatestAnalysis"); - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2010-12-25"); Project project = new Project("my:key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.isLatestAnalysis(), is(true)); } @@ -203,11 +192,11 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { public void isLatestAnalysisIfNeverAnalysed() { setupData("isLatestAnalysisIfNeverAnalysed"); - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2010-12-25"); Project project = new Project("my:key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.isLatestAnalysis(), is(true)); } @@ -216,11 +205,11 @@ public class ProjectConfiguratorTest extends AbstractDbUnitTestCase { public void isNotLatestAnalysis() { setupData("isNotLatestAnalysis"); - PropertiesConfiguration configuration = new PropertiesConfiguration(); + Settings configuration = new Settings(); configuration.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2005-12-25"); Project project = new Project("my:key"); - configurator.configure(project, configuration); + new ProjectConfigurator(getSession(), configuration).configure(project); assertThat(project.isLatestAnalysis(), is(false)); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/ProjectTreeTest.java b/sonar-batch/src/test/java/org/sonar/batch/ProjectTreeTest.java index 35fbd0c1bfb..093de7fab3c 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/ProjectTreeTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/ProjectTreeTest.java @@ -133,8 +133,4 @@ public class ProjectTreeTest extends AbstractDbUnitTestCase { return new Project("org.example:" + artifactId).setPom(pom).setConfiguration(new PropertiesConfiguration()); } - - private ProjectConfigurator newConfigurator() { - return new ProjectConfigurator(getSession()); - } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java b/sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java index a52d5d829c3..913c3dc819b 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java @@ -19,9 +19,9 @@ */ package org.sonar.batch; -import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Test; import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; import java.text.ParseException; @@ -32,13 +32,13 @@ public class ServerMetadataTest { @Test public void testLoadProperties() throws ParseException { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.SERVER_ID, "123"); - conf.setProperty(CoreProperties.SERVER_VERSION, "2.2"); - conf.setProperty(CoreProperties.SERVER_STARTTIME, "2010-05-18T17:59:00+0000"); - conf.setProperty("sonar.host.url", "http://foo.com"); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.SERVER_ID, "123"); + settings.setProperty(CoreProperties.SERVER_VERSION, "2.2"); + settings.setProperty(CoreProperties.SERVER_STARTTIME, "2010-05-18T17:59:00+0000"); + settings.setProperty("sonar.host.url", "http://foo.com"); - ServerMetadata server = new ServerMetadata(conf); + ServerMetadata server = new ServerMetadata(settings); assertThat(server.getId(), is("123")); assertThat(server.getVersion(), is("2.2")); @@ -52,10 +52,10 @@ public class ServerMetadataTest { */ @Test public void urlMustNotEndWithSlash() throws ParseException { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty("sonar.host.url", "http://localhost:80/"); + Settings settings = new Settings(); + settings.setProperty("sonar.host.url", "http://localhost:80/"); - ServerMetadata server = new ServerMetadata(conf); + ServerMetadata server = new ServerMetadata(settings); assertThat(server.getURL(), is("http://localhost:80")); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionInstallerTest.java index 10c19e6d415..c4c013d3632 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionInstallerTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionInstallerTest.java @@ -19,14 +19,17 @@ */ package org.sonar.batch.bootstrap; +import com.google.common.collect.Maps; import org.junit.Test; import org.sonar.api.*; import org.sonar.api.batch.CoverageExtension; import org.sonar.api.batch.InstantiationStrategy; +import org.sonar.api.platform.PluginMetadata; import org.sonar.batch.bootstrapper.EnvironmentInformation; import java.util.Arrays; import java.util.List; +import java.util.Map; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; @@ -36,51 +39,53 @@ import static org.mockito.Mockito.when; public class BatchExtensionInstallerTest { + private static final PluginMetadata METADATA = mock(PluginMetadata.class); + + private static Map newPlugin(final Class... classes) { + Map result = Maps.newHashMap(); + result.put(METADATA, + new SonarPlugin() { + public List getExtensions() { + return Arrays.asList(classes); + } + } + ); + return result; + } + @Test public void shouldInstallExtensionsWithBatchInstantiationStrategy() { BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); - when(pluginRepository.getPlugins()).thenReturn(Arrays.asList((Plugin) new SonarPlugin() { - public List getExtensions() { - return Arrays.asList(BatchService.class, ProjectService.class, ServerService.class); - } - })); + when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(BatchService.class, ProjectService.class, ServerService.class)); Module module = new FakeModule().init(); BatchExtensionInstaller installer = new BatchExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new DryRun(false)); installer.install(module); - assertThat(module.getComponent(BatchService.class), not(nullValue())); - assertThat(module.getComponent(ProjectService.class), nullValue()); - assertThat(module.getComponent(ServerService.class), nullValue()); + assertThat(module.getComponentByType(BatchService.class), not(nullValue())); + assertThat(module.getComponentByType(ProjectService.class), nullValue()); + assertThat(module.getComponentByType(ServerService.class), nullValue()); } @Test public void shouldInstallProvidersWithBatchInstantiationStrategy() { BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); - when(pluginRepository.getPlugins()).thenReturn(Arrays.asList((Plugin) new SonarPlugin(){ - public List getExtensions() { - return Arrays.asList(BatchServiceProvider.class, ProjectServiceProvider.class); - } - })); + when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(BatchServiceProvider.class, ProjectServiceProvider.class)); Module module = new FakeModule().init(); BatchExtensionInstaller installer = new BatchExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new DryRun(false)); installer.install(module); - assertThat(module.getComponent(BatchService.class), not(nullValue())); - assertThat(module.getComponent(ProjectService.class), nullValue()); - assertThat(module.getComponent(ServerService.class), nullValue()); + assertThat(module.getComponentByType(BatchService.class), not(nullValue())); + assertThat(module.getComponentByType(ProjectService.class), nullValue()); + assertThat(module.getComponentByType(ServerService.class), nullValue()); } @Test(expected = IllegalArgumentException.class) public void shouldNotSupportCoverageExtensionsWithBatchInstantiationStrategy() { // the reason is that CoverageExtensions currently depend on Project BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); - when(pluginRepository.getPlugins()).thenReturn(Arrays.asList((Plugin) new SonarPlugin(){ - public List getExtensions() { - return Arrays.asList(InvalidCoverageExtension.class); - } - })); + when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(InvalidCoverageExtension.class)); Module module = new FakeModule().init(); BatchExtensionInstaller installer = new BatchExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new DryRun(false)); diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java index 00b291a2279..40ed3add328 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java @@ -26,6 +26,7 @@ import org.hamcrest.Matchers; import org.junit.After; import org.junit.Test; import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; import org.sonar.core.plugins.RemotePlugin; import java.io.File; @@ -57,7 +58,7 @@ public class BatchPluginRepositoryTest { ArtifactDownloader downloader = mock(ArtifactDownloader.class); when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar")); - repository = new BatchPluginRepository(downloader, new PropertiesConfiguration()); + repository = new BatchPluginRepository(downloader, new Settings()); repository.doStart(Arrays.asList(checkstyle)); @@ -77,7 +78,7 @@ public class BatchPluginRepositoryTest { when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar")); when(downloader.downloadPlugin(checkstyleExt)).thenReturn(copyFiles("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar")); - repository = new BatchPluginRepository(downloader, new PropertiesConfiguration()); + repository = new BatchPluginRepository(downloader, new Settings()); repository.doStart(Arrays.asList(checkstyle, checkstyleExt)); @@ -97,7 +98,7 @@ public class BatchPluginRepositoryTest { ArtifactDownloader downloader = mock(ArtifactDownloader.class); when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar", "checkstyle-ext.xml")); - repository = new BatchPluginRepository(downloader, new PropertiesConfiguration()); + repository = new BatchPluginRepository(downloader, new Settings()); repository.doStart(Arrays.asList(checkstyle)); @@ -117,9 +118,9 @@ public class BatchPluginRepositoryTest { when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar")); when(downloader.downloadPlugin(checkstyleExt)).thenReturn(copyFiles("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar")); - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle"); - repository = new BatchPluginRepository(downloader, conf); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle"); + repository = new BatchPluginRepository(downloader, settings); repository.doStart(Arrays.asList(checkstyle, checkstyleExt)); @@ -142,41 +143,41 @@ public class BatchPluginRepositoryTest { @Test public void shouldAlwaysAcceptIfNoWhiteListAndBlackList() { - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), new PropertiesConfiguration()); + repository = new BatchPluginRepository(mock(ArtifactDownloader.class), new Settings()); assertThat(repository.isAccepted("pmd"), Matchers.is(true)); } @Test public void whiteListShouldTakePrecedenceOverBlackList() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - conf.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura,pmd"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), conf); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); + settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura,pmd"); + repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); assertThat(repository.isAccepted("pmd"), Matchers.is(true)); } @Test public void corePluginShouldAlwaysBeInWhiteList() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), conf); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); + repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); assertThat(repository.isAccepted("core"), Matchers.is(true)); } @Test public void corePluginShouldNeverBeInBlackList() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "core,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), conf); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "core,findbugs"); + repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); assertThat(repository.isAccepted("core"), Matchers.is(true)); } @Test public void shouldCheckWhitelist() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), conf); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); + repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); assertThat(repository.isAccepted("checkstyle"), Matchers.is(true)); assertThat(repository.isAccepted("pmd"), Matchers.is(true)); @@ -185,9 +186,9 @@ public class BatchPluginRepositoryTest { @Test public void shouldCheckBlackListIfNoWhiteList() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), conf); + Settings settings = new Settings(); + settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); + repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); assertThat(repository.isAccepted("checkstyle"), Matchers.is(false)); assertThat(repository.isAccepted("pmd"), Matchers.is(false)); diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DryRunTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DryRunTest.java index 5b278b0285d..a6acd28fd37 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DryRunTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DryRunTest.java @@ -19,27 +19,27 @@ */ package org.sonar.batch.bootstrap; -import org.apache.commons.configuration.PropertiesConfiguration; import org.hamcrest.core.Is; import org.junit.Test; +import org.sonar.api.config.Settings; import static org.junit.Assert.assertThat; public class DryRunTest { @Test - public void shouldReadConfiguration() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - conf.setProperty("sonar.dryRun", "true"); - assertThat(new DryRun(conf).isEnabled(), Is.is(true)); + public void shouldReadSettings() { + Settings settings = Settings.createForComponent(DryRun.class); + settings.setProperty("sonar.dryRun", true); + assertThat(new DryRun(settings).isEnabled(), Is.is(true)); - conf.setProperty("sonar.dryRun", "false"); - assertThat(new DryRun(conf).isEnabled(), Is.is(false)); + settings.setProperty("sonar.dryRun", false); + assertThat(new DryRun(settings).isEnabled(), Is.is(false)); } @Test public void shouldNotEnableDryRunByDefault() { - PropertiesConfiguration conf = new PropertiesConfiguration(); - assertThat(new DryRun(conf).isEnabled(), Is.is(false)); + Settings settings = Settings.createForComponent(DryRun.class); + assertThat(new DryRun(settings).isEnabled(), Is.is(false)); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ModuleTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ModuleTest.java index 60fc585dd0b..5d7accba6cc 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ModuleTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ModuleTest.java @@ -22,6 +22,7 @@ package org.sonar.batch.bootstrap; import org.hamcrest.Matchers; import org.junit.Test; +import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; @@ -33,10 +34,10 @@ public class ModuleTest { public void shouldInitModule() { Module module = new FakeModule(FakeService.class).init(); - FakeService service = module.getComponent(FakeService.class); + FakeService service = module.getComponentByType(FakeService.class); assertThat(service, not(nullValue())); assertThat(service.started, is(false)); - assertThat(module.getContainer(), not(nullValue())); + assertThat(module.container, notNullValue()); } @Test @@ -44,7 +45,7 @@ public class ModuleTest { Module module = new FakeModule(FakeService.class).init(); module.start(); - FakeService service = module.getComponent(FakeService.class); + FakeService service = module.getComponentByType(FakeService.class); assertThat(service.started, is(true)); module.stop(); @@ -68,7 +69,7 @@ public class ModuleTest { public void componentsShouldBeSingletons() { Module module = new FakeModule(FakeService.class).init(); - assertThat(module.getComponent(FakeService.class) == module.getComponent(FakeService.class), is(true)); + assertThat(module.getComponentByType(FakeService.class) == module.getComponentByType(FakeService.class), is(true)); } @Test @@ -78,16 +79,16 @@ public class ModuleTest { Module child = parent.installChild(new FakeModule(ChildService.class)); - assertThat(parent.getComponent(ChildService.class), Matchers.nullValue());// child not accessible from parent - assertThat(child.getComponent(FakeService.class), not(nullValue())); - assertThat(child.getComponent(ChildService.class).started, is(false)); - assertThat(child.getComponent(ChildService.class).dependency, not(nullValue())); + assertThat(parent.getComponentByType(ChildService.class), Matchers.nullValue());// child not accessible from parent + assertThat(child.getComponentByType(FakeService.class), not(nullValue())); + assertThat(child.getComponentByType(ChildService.class).started, is(false)); + assertThat(child.getComponentByType(ChildService.class).dependency, not(nullValue())); child.start(); - assertThat(child.getComponent(ChildService.class).started, is(true)); + assertThat(child.getComponentByType(ChildService.class).started, is(true)); child.stop(); - assertThat(child.getComponent(ChildService.class).started, is(false)); + assertThat(child.getComponentByType(ChildService.class).started, is(false)); } public static class FakeModule extends Module { @@ -100,7 +101,7 @@ public class ModuleTest { @Override protected void configure() { for (Class component : components) { - addComponent(component); + addCoreSingleton(component); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExtensionInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExtensionInstallerTest.java index 9e9fcd60fa6..1148116b2e1 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExtensionInstallerTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExtensionInstallerTest.java @@ -70,9 +70,9 @@ public class ProjectExtensionInstallerTest { installer.install(module, new Project("foo")); - assertThat(module.getComponent(BatchService.class), nullValue()); - assertThat(module.getComponent(ProjectService.class), not(nullValue())); - assertThat(module.getComponent(ServerService.class), nullValue()); + assertThat(module.getComponentByType(BatchService.class), nullValue()); + assertThat(module.getComponentByType(ProjectService.class), not(nullValue())); + assertThat(module.getComponentByType(ServerService.class), nullValue()); } @Test @@ -90,8 +90,8 @@ public class ProjectExtensionInstallerTest { installer.install(module, new Project("foo")); - assertThat(module.getComponent(MavenService.class), nullValue()); - assertThat(module.getComponent(BuildToolService.class), not(nullValue())); + assertThat(module.getComponentByType(MavenService.class), nullValue()); + assertThat(module.getComponentByType(BuildToolService.class), not(nullValue())); } diff --git a/sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java b/sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java new file mode 100644 index 00000000000..bf4eda351a4 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java @@ -0,0 +1,125 @@ +/* + * 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.core.config; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.text.StrSubstitutor; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.configuration.Property; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.jpa.session.DatabaseSessionFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +/** + * @since 2.12 + */ +public final class ConfigurationUtils { + + private ConfigurationUtils() { + } + + public static void copyProperties(Properties from, Map to) { + for (Map.Entry entry : from.entrySet()) { + String key = (String) entry.getKey(); + to.put(key, entry.getValue().toString()); + } + } + + public static Properties openProperties(File file) throws IOException { + FileInputStream input = FileUtils.openInputStream(file); + return openInputStream(input); + } + + /** + * Note that the input stream is closed in this method. + */ + public static Properties openInputStream(InputStream input) throws IOException { + try { + Properties p = new Properties(); + p.load(input); + return p; + + } finally { + IOUtils.closeQuietly(input); + } + } + + public static Properties interpolateEnvVariables(Properties properties) { + return interpolateVariables(properties, System.getenv()); + } + + public static Properties interpolateVariables(Properties properties, Map variables) { + Properties result = new Properties(); + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + String value = (String) properties.get(key); + String interpolatedValue = StrSubstitutor.replace(value, variables, "${env:", "}"); + result.setProperty(key, interpolatedValue); + } + return result; + } + + public static List getProjectProperties(DatabaseSessionFactory dbFactory, String moduleKey) { + DatabaseSession session = prepareDbSession(dbFactory); + ResourceModel resource = session.getSingleResult(ResourceModel.class, "key", moduleKey); + if (resource != null) { + return session + .createQuery("from " + Property.class.getSimpleName() + " p where p.resourceId=:resourceId and p.userId is null") + .setParameter("resourceId", resource.getId()) + .getResultList(); + + } + return Collections.emptyList(); + } + + public static List getGlobalProperties(DatabaseSessionFactory dbFactory) { + DatabaseSession session = prepareDbSession(dbFactory); + return session + .createQuery("from " + Property.class.getSimpleName() + " p where p.resourceId is null and p.userId is null") + .getResultList(); + + } + + private static DatabaseSession prepareDbSession(DatabaseSessionFactory dbFactory) { + DatabaseSession session = dbFactory.getSession(); + // Ugly workaround before the move to myBatis + // Session is not up-to-date when Ruby on Rails inserts new rows in its own transaction. Seems like + // Hibernate keeps a cache... + session.commit(); + return session; + } + + public static void copyToCommonsConfiguration(Map input, Configuration commonsConfig) { + // update deprecated configuration + commonsConfig.clear(); + for (Map.Entry entry : input.entrySet()) { + String key = entry.getKey(); + commonsConfig.setProperty(key, entry.getValue()); + } + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java b/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java index 866bb056ece..687576e5650 100644 --- a/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java +++ b/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java @@ -17,7 +17,6 @@ * 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.plugins; import com.google.common.collect.Lists; diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java b/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java index e543fecc28f..0b27ec5c554 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/AbstractDatabaseConnector.java @@ -24,6 +24,7 @@ import org.apache.commons.lang.StringUtils; import org.hibernate.cfg.Environment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; import org.sonar.api.utils.Logs; import org.sonar.jpa.dialect.Dialect; @@ -36,6 +37,7 @@ import javax.persistence.Persistence; import java.sql.Connection; import java.sql.SQLException; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -43,16 +45,15 @@ public abstract class AbstractDatabaseConnector implements DatabaseConnector { protected static final Logger LOG_SQL = LoggerFactory.getLogger("org.hibernate.SQL"); protected static final Logger LOG = LoggerFactory.getLogger(AbstractDatabaseConnector.class); - private Configuration configuration = null; + protected Settings configuration = null; private EntityManagerFactory factory = null; private int databaseVersion = SchemaMigration.VERSION_UNKNOWN; private boolean operational = false; private boolean started = false; private boolean startsFailIfSchemaOutdated; - private Integer transactionIsolation = null; private Dialect dialect = null; - protected AbstractDatabaseConnector(Configuration configuration, boolean startsFailIfSchemaOutdated) { + protected AbstractDatabaseConnector(Settings configuration, boolean startsFailIfSchemaOutdated) { this.configuration = configuration; this.startsFailIfSchemaOutdated = startsFailIfSchemaOutdated; } @@ -60,14 +61,6 @@ public abstract class AbstractDatabaseConnector implements DatabaseConnector { protected AbstractDatabaseConnector() { } - public Configuration getConfiguration() { - return configuration; - } - - public void setConfiguration(Configuration configuration) { - this.configuration = configuration; - } - public String getDialectId() { return dialect.getId(); } @@ -86,18 +79,8 @@ public abstract class AbstractDatabaseConnector implements DatabaseConnector { return started; } - /** - * Get the JDBC transaction isolation defined by the configuration - * - * @return JDBC transaction isolation - */ - public final Integer getTransactionIsolation() { - return transactionIsolation; - } - public void start() { if (!started) { - transactionIsolation = configuration.getInteger(DatabaseProperties.PROP_ISOLATION, null /* use driver default setting */); String jdbcConnectionUrl = testConnection(); dialect = DialectRepository.find(configuration.getString("sonar.jdbc.dialect"), jdbcConnectionUrl); LoggerFactory.getLogger("org.sonar.INFO").info("Database dialect class " + dialect.getClass().getName()); @@ -152,21 +135,15 @@ public abstract class AbstractDatabaseConnector implements DatabaseConnector { protected Properties getHibernateProperties() { Properties props = new Properties(); - if (transactionIsolation != null) { - props.put("hibernate.connection.isolation", Integer.toString(transactionIsolation)); - } - props.put("hibernate.hbm2ddl.auto", getConfiguration().getString(DatabaseProperties.PROP_HIBERNATE_HBM2DLL, "validate")); + props.put("hibernate.hbm2ddl.auto", StringUtils.defaultString(configuration.getString(DatabaseProperties.PROP_HIBERNATE_HBM2DLL), "validate")); props.put(Environment.DIALECT, getDialectClass()); - props.put("hibernate.generate_statistics", getConfiguration().getBoolean(DatabaseProperties.PROP_HIBERNATE_GENERATE_STATISTICS, false)); + props.put("hibernate.generate_statistics", configuration.getBoolean(DatabaseProperties.PROP_HIBERNATE_GENERATE_STATISTICS)); props.put("hibernate.show_sql", Boolean.valueOf(LOG_SQL.isDebugEnabled()).toString()); - Configuration subset = getConfiguration().subset("sonar.hibernate"); - for (Iterator keys = subset.getKeys(); keys.hasNext();) { - String key = (String) keys.next(); - if (StringUtils.isNotBlank((String) subset.getProperty(key))) { - props.put("hibernate." + key, subset.getProperty(key)); - } + List hibernateKeys = configuration.getKeysStartingWith("sonar.hibernate."); + for (String hibernateKey : hibernateKeys) { + props.put(StringUtils.removeStart(hibernateKey, "sonar."), configuration.getString(hibernateKey)); } // custom impl setup diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/DriverDatabaseConnector.java b/sonar-core/src/main/java/org/sonar/jpa/session/DriverDatabaseConnector.java index 00e91fd8f38..a2d6c619a89 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/DriverDatabaseConnector.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/DriverDatabaseConnector.java @@ -19,8 +19,8 @@ */ package org.sonar.jpa.session; -import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; import java.sql.Connection; @@ -35,20 +35,20 @@ public class DriverDatabaseConnector extends AbstractDatabaseConnector { private ClassLoader classloader; private boolean driverProxyRegistered = false; - public DriverDatabaseConnector(Configuration configuration) { + public DriverDatabaseConnector(Settings configuration) { super(configuration, true); this.classloader = getClass().getClassLoader(); } - public DriverDatabaseConnector(Configuration configuration, ClassLoader classloader) { + public DriverDatabaseConnector(Settings configuration, ClassLoader classloader) { super(configuration, true); this.classloader = classloader; } public String getDriver() { - String driver = getConfiguration().getString(DatabaseProperties.PROP_DRIVER); + String driver = configuration.getString(DatabaseProperties.PROP_DRIVER); if (driver == null) { - driver = getConfiguration().getString(DatabaseProperties.PROP_DRIVER_DEPRECATED); + driver = configuration.getString(DatabaseProperties.PROP_DRIVER_DEPRECATED); } if (driver == null) { driver = DatabaseProperties.PROP_DRIVER_DEFAULT_VALUE; @@ -57,13 +57,13 @@ public class DriverDatabaseConnector extends AbstractDatabaseConnector { } public String getUrl() { - return getConfiguration().getString(DatabaseProperties.PROP_URL, DatabaseProperties.PROP_URL_DEFAULT_VALUE); + return StringUtils.defaultString(configuration.getString(DatabaseProperties.PROP_URL), DatabaseProperties.PROP_URL_DEFAULT_VALUE); } public String getUsername() { - String username = getConfiguration().getString(DatabaseProperties.PROP_USER); + String username = configuration.getString(DatabaseProperties.PROP_USER); if (username == null) { - username = getConfiguration().getString(DatabaseProperties.PROP_USER_DEPRECATED); + username = configuration.getString(DatabaseProperties.PROP_USER_DEPRECATED); } if (username == null) { username = DatabaseProperties.PROP_USER_DEFAULT_VALUE; @@ -72,7 +72,7 @@ public class DriverDatabaseConnector extends AbstractDatabaseConnector { } public String getPassword() { - return getConfiguration().getString(DatabaseProperties.PROP_PASSWORD, DatabaseProperties.PROP_PASSWORD_DEFAULT_VALUE); + return StringUtils.defaultString(configuration.getString(DatabaseProperties.PROP_PASSWORD), DatabaseProperties.PROP_PASSWORD_DEFAULT_VALUE); } public Connection getConnection() throws SQLException { diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/MemoryDatabaseConnector.java b/sonar-core/src/main/java/org/sonar/jpa/session/MemoryDatabaseConnector.java index 5e9cfa2f09f..863e7ebe7fd 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/MemoryDatabaseConnector.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/MemoryDatabaseConnector.java @@ -19,8 +19,7 @@ */ package org.sonar.jpa.session; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.PropertiesConfiguration; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; import org.sonar.jpa.entity.SchemaMigration; @@ -37,7 +36,7 @@ public class MemoryDatabaseConnector extends DriverDatabaseConnector { private int version; - public MemoryDatabaseConnector(Configuration config) { + public MemoryDatabaseConnector(Settings config) { super(config); version = SchemaMigration.LAST_VERSION; } @@ -51,8 +50,8 @@ public class MemoryDatabaseConnector extends DriverDatabaseConnector { this.version = version; } - protected static Configuration getInMemoryConfiguration(boolean createSchema) { - PropertiesConfiguration conf = new PropertiesConfiguration(); + protected static Settings getInMemoryConfiguration(boolean createSchema) { + Settings conf = new Settings(); conf.setProperty(DatabaseProperties.PROP_URL, URL); conf.setProperty(DatabaseProperties.PROP_DRIVER, DRIVER); conf.setProperty(DatabaseProperties.PROP_USER, USER); diff --git a/sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java new file mode 100644 index 00000000000..5528102bd4e --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/config/ConfigurationUtilsTest.java @@ -0,0 +1,73 @@ +/* + * 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.core.config; + +import com.google.common.collect.Maps; +import org.junit.Test; + +import java.util.Map; +import java.util.Properties; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class ConfigurationUtilsTest { + @Test + public void shouldInterpolateVariables() { + Properties input = new Properties(); + input.setProperty("hello", "world"); + input.setProperty("url", "${env:SONAR_JDBC_URL}"); + input.setProperty("do_not_change", "${SONAR_JDBC_URL}"); + Map variables = Maps.newHashMap(); + variables.put("SONAR_JDBC_URL", "jdbc:derby:mem"); + + Properties output = ConfigurationUtils.interpolateVariables(input, variables); + + assertThat(output.size(), is(3)); + assertThat(output.getProperty("hello"), is("world")); + assertThat(output.getProperty("url"), is("jdbc:derby:mem")); + assertThat(output.getProperty("do_not_change"), is("${SONAR_JDBC_URL}")); + + // input is not changed + assertThat(input.size(), is(3)); + assertThat(input.getProperty("hello"), is("world")); + assertThat(input.getProperty("url"), is("${env:SONAR_JDBC_URL}")); + assertThat(input.getProperty("do_not_change"), is("${SONAR_JDBC_URL}")); + } + + @Test + public void shouldCopyProperties() { + Properties input = new Properties(); + input.setProperty("hello", "world"); + input.setProperty("foo", "bar"); + Map output = Maps.newHashMap(); + + ConfigurationUtils.copyProperties(input, output); + + assertThat(output.size(), is(2)); + assertThat(output.get("hello"), is("world")); + assertThat(output.get("foo"), is("bar")); + + // input is not changed + assertThat(input.size(), is(2)); + assertThat(input.getProperty("hello"), is("world")); + assertThat(input.getProperty("foo"), is("bar")); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java b/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java index afc386a9d8e..7d08e633669 100644 --- a/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java +++ b/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java @@ -27,7 +27,6 @@ import org.sonar.api.BatchExtension; import org.sonar.api.ExtensionProvider; import org.sonar.api.Plugin; import org.sonar.api.ServerExtension; -import org.sonar.api.utils.IocContainer; import java.util.Arrays; import java.util.Collection; diff --git a/sonar-core/src/test/java/org/sonar/jpa/session/AbstractDatabaseConnectorTest.java b/sonar-core/src/test/java/org/sonar/jpa/session/AbstractDatabaseConnectorTest.java index f584eb4b72b..8ee37d71933 100644 --- a/sonar-core/src/test/java/org/sonar/jpa/session/AbstractDatabaseConnectorTest.java +++ b/sonar-core/src/test/java/org/sonar/jpa/session/AbstractDatabaseConnectorTest.java @@ -24,6 +24,7 @@ import org.apache.commons.configuration.PropertiesConfiguration; import org.hamcrest.Matchers; import org.junit.Test; import org.mockito.Mockito; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; import org.sonar.jpa.dialect.HsqlDb; import org.sonar.jpa.dialect.Oracle; @@ -49,7 +50,7 @@ public class AbstractDatabaseConnectorTest { @Test public void useConfiguredDialectByDefault() { - Configuration conf = MemoryDatabaseConnector.getInMemoryConfiguration(false); + Settings conf = MemoryDatabaseConnector.getInMemoryConfiguration(false); conf.setProperty(DatabaseProperties.PROP_DIALECT, DatabaseProperties.DIALECT_ORACLE); TestDatabaseConnector connector = new TestDatabaseConnector(conf); @@ -60,7 +61,7 @@ public class AbstractDatabaseConnectorTest { @Test public void getHibernateProperties() { - PropertiesConfiguration conf = new PropertiesConfiguration(); + Settings conf = new Settings(); conf.setProperty("sonar.foo", "foo value"); // all properties prefixed by sonar.hibernate are propagated to hibernate configuration (the prefix "sonar." is removed) @@ -84,7 +85,7 @@ public class AbstractDatabaseConnectorTest { private class TestDatabaseConnector extends AbstractDatabaseConnector { - public TestDatabaseConnector(Configuration configuration) { + public TestDatabaseConnector(Settings configuration) { super(configuration, false); } diff --git a/sonar-core/src/test/java/org/sonar/jpa/session/DriverDatabaseConnectorTest.java b/sonar-core/src/test/java/org/sonar/jpa/session/DriverDatabaseConnectorTest.java index dfc0716eb0d..82fd8c4e41c 100644 --- a/sonar-core/src/test/java/org/sonar/jpa/session/DriverDatabaseConnectorTest.java +++ b/sonar-core/src/test/java/org/sonar/jpa/session/DriverDatabaseConnectorTest.java @@ -23,6 +23,7 @@ import org.apache.commons.configuration.PropertiesConfiguration; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Test; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; import java.sql.SQLException; @@ -43,11 +44,10 @@ public class DriverDatabaseConnectorTest { @Test(expected = DatabaseException.class) public void failsIfUnvalidConfiguration() throws SQLException { - PropertiesConfiguration conf = new PropertiesConfiguration(); + Settings conf = new Settings(); conf.setProperty(DatabaseProperties.PROP_URL, "jdbc:foo:bar//xxx"); conf.setProperty(DatabaseProperties.PROP_DRIVER, MemoryDatabaseConnector.DRIVER); conf.setProperty(DatabaseProperties.PROP_USER, "sa"); - conf.setProperty(DatabaseProperties.PROP_PASSWORD, null); connector = new DriverDatabaseConnector(conf); try { connector.start(); @@ -81,7 +81,7 @@ public class DriverDatabaseConnectorTest { @Test public void deprecatedParametersAreStillValid() { - PropertiesConfiguration conf = new PropertiesConfiguration(); + Settings conf = new Settings(); conf.setProperty(DatabaseProperties.PROP_DRIVER_DEPRECATED, MemoryDatabaseConnector.DRIVER); conf.setProperty(DatabaseProperties.PROP_USER_DEPRECATED, "freddy"); connector = new DriverDatabaseConnector(conf); diff --git a/sonar-maven-plugin/src/main/java/org/sonar/maven/SonarMojo.java b/sonar-maven-plugin/src/main/java/org/sonar/maven/SonarMojo.java index 75673c63b06..6b78f9b463d 100644 --- a/sonar-maven-plugin/src/main/java/org/sonar/maven/SonarMojo.java +++ b/sonar-maven-plugin/src/main/java/org/sonar/maven/SonarMojo.java @@ -147,7 +147,7 @@ public final class SonarMojo extends AbstractMojo { ProjectDefinition def = MavenProjectConverter.convert(session.getSortedProjects(), project); ProjectReactor reactor = new ProjectReactor(def); - Batch batch = Batch.create(reactor, getInitialConfiguration(), + Batch batch = Batch.create(reactor, null, session, getLog(), lifecycleExecutor, pluginManager, artifactFactory, localRepository, artifactMetadataSource, artifactCollector, dependencyTreeBuilder, projectBuilder, getEnvironmentInformation(), Maven2PluginExecutor.class); diff --git a/sonar-maven3-plugin/src/main/java/org/sonar/maven3/SonarMojo.java b/sonar-maven3-plugin/src/main/java/org/sonar/maven3/SonarMojo.java index f4173290c11..001378c7bb7 100644 --- a/sonar-maven3-plugin/src/main/java/org/sonar/maven3/SonarMojo.java +++ b/sonar-maven3-plugin/src/main/java/org/sonar/maven3/SonarMojo.java @@ -22,7 +22,6 @@ package org.sonar.maven3; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; -import org.apache.commons.configuration.*; import org.apache.commons.io.IOUtils; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; @@ -43,6 +42,7 @@ import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.batch.Batch; import org.sonar.batch.MavenProjectConverter; import org.sonar.batch.bootstrapper.EnvironmentInformation; + import java.io.InputStream; /** @@ -140,7 +140,7 @@ public final class SonarMojo extends AbstractMojo { ProjectDefinition def = MavenProjectConverter.convert(session.getSortedProjects(), project); ProjectReactor reactor = new ProjectReactor(def); - Batch batch = Batch.create(reactor, getInitialConfiguration(), + Batch batch = Batch.create(reactor, null, session, getLog(), lifecycleExecutor, artifactFactory, localRepository, artifactMetadataSource, artifactCollector, dependencyTreeBuilder, projectBuilder, getEnvironmentInformation(), Maven3PluginExecutor.class); @@ -170,11 +170,4 @@ public final class SonarMojo extends AbstractMojo { } } - private Configuration getInitialConfiguration() { - CompositeConfiguration configuration = new CompositeConfiguration(); - configuration.addConfiguration(new SystemConfiguration()); - configuration.addConfiguration(new EnvironmentConfiguration()); - configuration.addConfiguration(new MapConfiguration(project.getModel().getProperties())); - return configuration; - } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/BatchExtensionDictionnary.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/BatchExtensionDictionnary.java index dddea1ccc0b..e7b62cf8dde 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/BatchExtensionDictionnary.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/BatchExtensionDictionnary.java @@ -23,14 +23,12 @@ import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import org.apache.commons.lang.ClassUtils; -import org.picocontainer.MutablePicoContainer; -import org.picocontainer.PicoContainer; import org.sonar.api.BatchExtension; import org.sonar.api.batch.maven.DependsUponMavenPlugin; import org.sonar.api.batch.maven.MavenPluginHandler; +import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.api.utils.AnnotationUtils; -import org.sonar.api.utils.IocContainer; import org.sonar.api.utils.dag.DirectAcyclicGraph; import java.lang.annotation.Annotation; @@ -45,14 +43,10 @@ import java.util.List; */ public class BatchExtensionDictionnary { - private MutablePicoContainer picoContainer; + private ComponentContainer componentContainer; - public BatchExtensionDictionnary(IocContainer iocContainer) { - this.picoContainer = iocContainer.getPicoContainer(); - } - - public BatchExtensionDictionnary(MutablePicoContainer picoContainer) { - this.picoContainer = picoContainer; + public BatchExtensionDictionnary(ComponentContainer componentContainer) { + this.componentContainer = componentContainer; } public Collection select(Class type) { @@ -88,14 +82,14 @@ public class BatchExtensionDictionnary { private List getExtensions() { List extensions = Lists.newArrayList(); - completeBatchExtensions(picoContainer, extensions); + completeBatchExtensions(componentContainer, extensions); return extensions; } - private void completeBatchExtensions(PicoContainer picoContainer, List extensions) { - if (picoContainer!=null) { - extensions.addAll(picoContainer.getComponents(BatchExtension.class)); - completeBatchExtensions(picoContainer.getParent(), extensions); + private static void completeBatchExtensions(ComponentContainer container, List extensions) { + if (container != null) { + extensions.addAll(container.getComponentsByType(BatchExtension.class)); + completeBatchExtensions(container.getParent(), extensions); } } @@ -212,7 +206,7 @@ public class BatchExtensionDictionnary { if (result != null) { //TODO add arrays/collections of objects/classes if (result instanceof Class) { - results.addAll(picoContainer.getComponents((Class) result)); + results.addAll(componentContainer.getComponentsByType((Class) result)); } else if (result instanceof Collection) { results.addAll((Collection) result); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java new file mode 100644 index 00000000000..8190e157a49 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java @@ -0,0 +1,114 @@ +/* + * 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.api.config; + +import com.google.common.collect.Maps; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.BatchComponent; +import org.sonar.api.Properties; +import org.sonar.api.Property; +import org.sonar.api.ServerComponent; +import org.sonar.api.utils.AnnotationUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +/** + * Metadata of all the properties declared by plugins + * + * @since 2.12 + */ +public final class PropertyDefinitions implements BatchComponent, ServerComponent { + + private Map properties = Maps.newHashMap(); + private Map categories = Maps.newHashMap(); + + public PropertyDefinitions(Object... components) { + if (components != null) { + addComponents(Arrays.asList(components)); + } + } + + public PropertyDefinitions addComponents(Collection components) { + return addComponents(components, ""); + } + + public PropertyDefinitions addComponents(Collection components, String defaultCategory) { + for (Object component : components) { + addComponent(component, defaultCategory); + } + return this; + } + + public PropertyDefinitions addComponent(Object object) { + return addComponent(object, ""); + } + + public PropertyDefinitions addComponent(Object component, String defaultCategory) { + Properties annotations = AnnotationUtils.getClassAnnotation(component, Properties.class); + if (annotations != null) { + for (Property property : annotations.value()) { + addProperty(property, defaultCategory); + } + } + Property annotation = AnnotationUtils.getClassAnnotation(component, Property.class); + if (annotation != null) { + addProperty(annotation, defaultCategory); + } + return this; + } + + PropertyDefinitions addProperty(Property property) { + return addProperty(property, ""); + } + + PropertyDefinitions addProperty(Property property, String defaultCategory) { + if (!properties.containsKey(property.key())) { + properties.put(property.key(), property); + categories.put(property.key(), StringUtils.defaultIfBlank(property.category(), defaultCategory)); + } + return this; + } + + public Property getProperty(String key) { + return properties.get(key); + } + + public Collection getProperties() { + return properties.values(); + } + + public String getDefaultValue(String key) { + Property prop = getProperty(key); + if (prop != null) { + return StringUtils.defaultIfEmpty(prop.defaultValue(), null); + } + return null; + } + + public String getCategory(String key) { + return categories.get(key); + } + + public String getCategory(Property prop) { + return getCategory(prop.key()); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java new file mode 100644 index 00000000000..fc626bb5f9f --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java @@ -0,0 +1,251 @@ +/* + * 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.api.config; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.BatchComponent; +import org.sonar.api.ServerComponent; +import org.sonar.api.utils.DateUtils; + +import java.util.*; + +/** + * Project Settings on batch side, Global Settings on server side. + *

+ * Replace the deprecated component org.apache.commons.configuration.Configuration + * + * @since 2.12 + */ +public class Settings implements BatchComponent, ServerComponent { + + protected Map properties = Maps.newHashMap(); + protected PropertyDefinitions definitions; + + public Settings() { + this(new PropertyDefinitions()); + } + + public Settings(PropertyDefinitions definitions) { + this.definitions = definitions; + } + + public final String getDefaultValue(String key) { + return definitions.getDefaultValue(key); + } + + public final boolean hasKey(String key) { + return properties.containsKey(key); + } + + public final boolean hasDefaultValue(String key) { + return StringUtils.isNotEmpty(getDefaultValue(key)); + } + + public final String getString(String key) { + String value = properties.get(key); + if (value==null) { + value = getDefaultValue(key); + } + return value; + } + + public final boolean getBoolean(String key) { + String value = getString(key); + return StringUtils.isNotEmpty(value) && Boolean.parseBoolean(value); + } + + public final int getInt(String key) { + String value = getString(key); + if (StringUtils.isNotEmpty(value)) { + return Integer.parseInt(value); + } + return 0; + } + + public final long getLong(String key) { + String value = getString(key); + if (StringUtils.isNotEmpty(value)) { + return Long.parseLong(value); + } + return 0L; + } + + public final Date getDate(String key) { + String value = getString(key); + if (StringUtils.isNotEmpty(value)) { + return DateUtils.parseDate(value); + } + return null; + } + + public final Date getDateTime(String key) { + String value = getString(key); + if (StringUtils.isNotEmpty(value)) { + return DateUtils.parseDateTime(value); + } + return null; + } + + public final String[] getStringArray(String key) { + return getStringArrayBySeparator(key, ","); + } + + public final String[] getStringArrayBySeparator(String key, String separator) { + String value = getString(key); + if (value != null) { + return StringUtils.splitByWholeSeparator(value, separator); + } + return ArrayUtils.EMPTY_STRING_ARRAY; + } + + public List getKeysStartingWith(String prefix) { + List result = Lists.newArrayList(); + for (String key : properties.keySet()) { + if (StringUtils.startsWith(key, prefix)) { + result.add(key); + } + } + return result; + } + + + + public final Settings appendProperty(String key, String value) { + String newValue = properties.get(key); + if (StringUtils.isEmpty(newValue)) { + newValue = value; + } else { + newValue += "," + value; + } + properties.put(key, newValue); + return this; + } + + public final Settings setProperty(String key, String value) { + if (!clearIfNullValue(key, value)) { + properties.put(key, value); + } + return this; + } + + public final Settings setProperty(String key, Boolean value) { + if (!clearIfNullValue(key, value)) { + properties.put(key, String.valueOf(value)); + } + return this; + } + + public final Settings setProperty(String key, Integer value) { + if (!clearIfNullValue(key, value)) { + properties.put(key, String.valueOf(value)); + } + return this; + } + + public final Settings setProperty(String key, Long value) { + if (!clearIfNullValue(key, value)) { + properties.put(key, String.valueOf(value)); + } + return this; + } + + public final Settings setProperty(String key, Double value) { + if (!clearIfNullValue(key, value)) { + properties.put(key, String.valueOf(value)); + } + return this; + } + + public final Settings setProperty(String key, Date date) { + return setProperty(key, date, false); + } + + public final Settings addProperties(Map props) { + properties.putAll(props); + return this; + } + + public final Settings addProperties(Properties props) { + for (Map.Entry entry : props.entrySet()) { + properties.put(entry.getKey().toString(), entry.getValue().toString()); + } + return this; + } + + public final Settings addSystemProperties() { + return addProperties(System.getProperties()); + } + + public final Settings addEnvironmentVariables() { + return addProperties(System.getenv()); + } + + public final Settings setProperties(Map props) { + properties = Maps.newHashMap(props); + return this; + } + + public final Settings setProperty(String key, Date date, boolean includeTime) { + if (!clearIfNullValue(key, date)) { + properties.put(key, includeTime ? DateUtils.formatDateTime(date) : DateUtils.formatDate(date)); + } + return this; + } + + public final Settings removeProperty(String key) { + properties.remove(key); + return this; + } + + public final Settings clear() { + properties.clear(); + return this; + } + + /** + * @return unmodifiable properties + */ + public final Map getProperties() { + return Collections.unmodifiableMap(properties); + } + + public final PropertyDefinitions getDefinitions() { + return definitions; + } + + private boolean clearIfNullValue(String key, Object value) { + if (value == null) { + properties.remove(key); + return true; + } + return false; + } + + /** + * Create empty settings. Definition of available properties is loaded from the given annotated class. + * This method is usually used by unit tests. + */ + public static Settings createForComponent(Object component) { + return new Settings(new PropertyDefinitions(component)); + } +} 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 new file mode 100644 index 00000000000..53734229b65 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java @@ -0,0 +1,164 @@ +/* + * 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.api.platform; + +import org.picocontainer.Characteristics; +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.BatchComponent; +import org.sonar.api.ServerComponent; +import org.sonar.api.config.PropertyDefinitions; + +/** + * @since 2.12 + */ +public class ComponentContainer implements BatchComponent, ServerComponent { + + ComponentContainer parent, child; // no need for multiple children + MutablePicoContainer pico; + PropertyDefinitions propertyDefinitions; + + /** + * Create root container + */ + public ComponentContainer() { + this.parent = null; + this.child = null; + this.pico = createPicoContainer(); + propertyDefinitions = new PropertyDefinitions(); + addSingleton(propertyDefinitions); + addSingleton(this); + } + + /** + * Create child container + */ + private ComponentContainer(ComponentContainer parent) { + this.parent = parent; + this.pico = parent.pico.makeChildContainer(); + this.parent.child = this; + this.propertyDefinitions = parent.propertyDefinitions; + addSingleton(this); + } + + /** + * 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() { + pico.start(); + return this; + } + + /** + * 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(); + return this; + } + + public final ComponentContainer addSingleton(Object component) { + return addComponent(component, true); + } + + /** + * @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) { + pico.as(singleton ? Characteristics.CACHE : Characteristics.NO_CACHE).addComponent(getComponentKey(component), component); + propertyDefinitions.addComponent(component); + return this; + } + + public final ComponentContainer addExtension(PluginMetadata plugin, Object extension) { + pico.as(Characteristics.CACHE).addComponent(getComponentKey(extension), extension); + declareExtension(plugin, extension); + return this; + } + + public final void declareExtension(PluginMetadata plugin, Object extension) { + propertyDefinitions.addComponent(extension, plugin.getName()); + } + + public final ComponentContainer addPicoAdapter(ComponentAdapter adapter) { + pico.addAdapter(adapter); + return this; + } + + public final T getComponentByType(Class tClass) { + return pico.getComponent(tClass); + } + + public final Object getComponentByKey(Object key) { + return pico.getComponent(key); + } + + public final java.util.List getComponentsByType(java.lang.Class tClass) { + return pico.getComponents(tClass); + } + + public final ComponentContainer removeChild() { + if (child != null) { + pico.removeChildContainer(child.pico); + child = null; + } + return this; + } + + public final ComponentContainer createChild() { + return new ComponentContainer(this); + } + + static MutablePicoContainer createPicoContainer() { + ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "dispose"); + return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, null); + } + + static Object getComponentKey(Object component) { + if (component instanceof Class) { + return component; + } + return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(component.toString()).toString(); + } + + public ComponentContainer getParent() { + return parent; + } + + public ComponentContainer getChild() { + return child; + } + + /** + * Warning - do not use. This method exists only for the backward-compatibility due to the suppression + * of {@link org.sonar.api.utils.IocContainer} + * @return + */ + public MutablePicoContainer getPicoContainer() { + return pico; + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Languages.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Languages.java index 03062e94de3..ab9d26fef38 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Languages.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Languages.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.google.common.collect.Maps; import org.apache.commons.lang.ArrayUtils; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; @@ -36,7 +37,7 @@ import org.sonar.api.ServerComponent; */ public class Languages implements BatchComponent, ServerComponent { - private final Map map = new HashMap(); + private final Map map = Maps.newHashMap(); /** * Creates a list of languages diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java index dda4c228c52..99432b0313f 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java @@ -420,7 +420,9 @@ public class Project extends Resource { /** * @return the project configuration + * @deprecated since 2.12. The component org.sonar.api.config.Settings must be used. */ + @Deprecated public Configuration getConfiguration() { return configuration; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java index 097fa7a2ba9..1893f02e5de 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java @@ -21,13 +21,12 @@ package org.sonar.api.utils; import com.google.common.base.Joiner; import com.google.common.collect.Lists; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; +import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; import java.io.File; @@ -39,7 +38,7 @@ import java.util.List; /** * This component downloads HTTP files - * + * * @since 2.2 */ public class HttpDownloader implements BatchComponent, ServerComponent { @@ -48,30 +47,23 @@ public class HttpDownloader implements BatchComponent, ServerComponent { private String userAgent; - public HttpDownloader(Server server, Configuration configuration) { - this(configuration, server.getVersion()); - } - - public HttpDownloader(Configuration configuration) { - this(configuration, null); + public HttpDownloader(Server server, Settings settings) { + this(settings, server.getVersion()); } - /** - * Should be package protected for unit tests only, but public is still required for jacoco 0.2. - */ - public HttpDownloader() { - this(new PropertiesConfiguration(), null); + public HttpDownloader(Settings settings) { + this(settings, null); } - private HttpDownloader(Configuration configuration, String userAgent) { - initProxy(configuration); + private HttpDownloader(Settings settings, String userAgent) { + initProxy(settings); initUserAgent(userAgent); } - private void initProxy(Configuration configuration) { - propagateProxySystemProperties(configuration); - if (requiresProxyAuthentication(configuration)) { - registerProxyCredentials(configuration); + private void initProxy(Settings settings) { + propagateProxySystemProperties(settings); + if (requiresProxyAuthentication(settings)) { + registerProxyCredentials(settings); } } @@ -99,27 +91,27 @@ public class HttpDownloader implements BatchComponent, ServerComponent { return Joiner.on(", ").join(descriptions); } - private void registerProxyCredentials(Configuration configuration) { - Authenticator.setDefault(new ProxyAuthenticator(configuration.getString("http.proxyUser"), configuration + private void registerProxyCredentials(Settings settings) { + Authenticator.setDefault(new ProxyAuthenticator(settings.getString("http.proxyUser"), settings .getString("http.proxyPassword"))); } - private boolean requiresProxyAuthentication(Configuration configuration) { - return configuration.getString("http.proxyUser") != null; + private boolean requiresProxyAuthentication(Settings settings) { + return settings.getString("http.proxyUser") != null; } - private void propagateProxySystemProperties(Configuration configuration) { - propagateSystemProperty(configuration, "http.proxyHost"); - propagateSystemProperty(configuration, "http.proxyPort"); - propagateSystemProperty(configuration, "http.nonProxyHosts"); - propagateSystemProperty(configuration, "http.auth.ntlm.domain"); - propagateSystemProperty(configuration, "socksProxyHost"); - propagateSystemProperty(configuration, "socksProxyPort"); + private void propagateProxySystemProperties(Settings settings) { + propagateSystemProperty(settings, "http.proxyHost"); + propagateSystemProperty(settings, "http.proxyPort"); + propagateSystemProperty(settings, "http.nonProxyHosts"); + propagateSystemProperty(settings, "http.auth.ntlm.domain"); + propagateSystemProperty(settings, "socksProxyHost"); + propagateSystemProperty(settings, "socksProxyPort"); } - private void propagateSystemProperty(Configuration configuration, String key) { - if (configuration.getString(key) != null) { - System.setProperty(key, configuration.getString(key)); + private void propagateSystemProperty(Settings settings, String key) { + if (settings.getString(key) != null) { + System.setProperty(key, settings.getString(key)); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/IocContainer.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/IocContainer.java index 7791d04fd49..9d348f248c9 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/IocContainer.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/IocContainer.java @@ -25,12 +25,14 @@ import org.picocontainer.MutablePicoContainer; import org.picocontainer.behaviors.OptInCaching; import org.picocontainer.lifecycle.ReflectionLifecycleStrategy; import org.picocontainer.monitors.NullComponentMonitor; +import org.sonar.api.platform.ComponentContainer; /** * Proxy to inject the container as a component$ * * @since 1.10 + * @deprecated since 2.12. To be replaced by {@link org.sonar.api.platform.ComponentContainer} */ public class IocContainer { private final MutablePicoContainer pico; @@ -39,6 +41,10 @@ public class IocContainer { this.pico = pico; } + public IocContainer(ComponentContainer container) { + this.pico = container.getPicoContainer(); + } + public MutablePicoContainer getPicoContainer() { return pico; } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/BatchExtensionDictionnaryTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/BatchExtensionDictionnaryTest.java index 37e6e644c49..bda9de6d1bc 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/BatchExtensionDictionnaryTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/BatchExtensionDictionnaryTest.java @@ -21,16 +21,12 @@ package org.sonar.api.batch; import com.google.common.collect.Lists; import org.junit.Test; -import org.picocontainer.Characteristics; -import org.picocontainer.DefaultPicoContainer; -import org.picocontainer.PicoContainer; -import org.picocontainer.containers.TransientPicoContainer; import org.sonar.api.BatchExtension; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; +import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; -import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -44,10 +40,9 @@ import static org.mockito.Mockito.mock; public class BatchExtensionDictionnaryTest { private BatchExtensionDictionnary newSelector(BatchExtension... extensions) { - TransientPicoContainer iocContainer = new TransientPicoContainer(); - int key = 0; + ComponentContainer iocContainer = new ComponentContainer(); for (BatchExtension extension : extensions) { - iocContainer.addComponent(key++, extension); + iocContainer.addSingleton(extension); } return new BatchExtensionDictionnary(iocContainer); } @@ -67,14 +62,14 @@ public class BatchExtensionDictionnaryTest { @Test public void shouldSearchInParentContainers() { - TransientPicoContainer grandParent = new TransientPicoContainer(); - grandParent.as(Characteristics.CACHE).addComponent("ncloc", CoreMetrics.NCLOC); + ComponentContainer grandParent = new ComponentContainer(); + grandParent.addSingleton(CoreMetrics.NCLOC); - DefaultPicoContainer parent = (DefaultPicoContainer)grandParent.makeChildContainer(); - parent.as(Characteristics.CACHE).addComponent("coverage", CoreMetrics.COVERAGE); + ComponentContainer parent = grandParent.createChild(); + parent.addSingleton(CoreMetrics.COVERAGE); - DefaultPicoContainer child = (DefaultPicoContainer)parent.makeChildContainer(); - child.as(Characteristics.CACHE).addComponent("complexity", CoreMetrics.COMPLEXITY); + ComponentContainer child = parent.createChild(); + child.addSingleton(CoreMetrics.COMPLEXITY); BatchExtensionDictionnary dictionnary = new BatchExtensionDictionnary(child); assertThat(dictionnary.select(Metric.class).size(), is(3)); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java new file mode 100644 index 00000000000..857dbb82aed --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java @@ -0,0 +1,93 @@ +/* + * 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.api.config; + +import org.junit.Test; +import org.sonar.api.Properties; +import org.sonar.api.Property; + +import java.util.Arrays; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class PropertyDefinitionsTest { + + @Test + public void shouldInspectPluginObjects() { + PropertyDefinitions def = new PropertyDefinitions(new PluginWithProperty(), new PluginWithProperties()); + + assertProperties(def); + } + + @Test + public void shouldInspectPluginClasses() { + PropertyDefinitions def = new PropertyDefinitions(PluginWithProperty.class, PluginWithProperties.class); + + assertProperties(def); + } + + private void assertProperties(PropertyDefinitions def) { + assertThat(def.getProperty("foo").name(), is("Foo")); + assertThat(def.getProperty("one").name(), is("One")); + assertThat(def.getProperty("two").name(), is("Two")); + assertThat(def.getProperty("unknown"), nullValue()); + + assertThat(def.getDefaultValue("foo"), nullValue()); + assertThat(def.getDefaultValue("two"), is("2")); + + assertThat(def.getProperties().size(), is(3)); + } + + @Property(key = "foo", name = "Foo") + static final class PluginWithProperty { + } + + @Properties({ + @Property(key = "one", name = "One"), + @Property(key = "two", name = "Two", defaultValue = "2") + }) + static final class PluginWithProperties { + } + + + @Test + public void testCategories() { + PropertyDefinitions def = new PropertyDefinitions(Categories.class); + assertThat(def.getCategory("inCateg"), is("categ")); + assertThat(def.getCategory("noCateg"), is("")); + } + + @Test + public void testDefaultCategory() { + PropertyDefinitions def = new PropertyDefinitions(); + def.addComponent(Categories.class, "default"); + assertThat(def.getCategory("inCateg"), is("categ")); + assertThat(def.getCategory("noCateg"), is("default")); + } + + @Properties({ + @Property(key = "inCateg", name="In Categ", category = "categ"), + @Property(key = "noCateg", name="No categ") + }) + static final class Categories { + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java new file mode 100644 index 00000000000..c34f1278ca4 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java @@ -0,0 +1,124 @@ +/* + * 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.api.config; + +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.Property; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SettingsTest { + + private PropertyDefinitions definitions; + + @Before + public void initDefinitions() { + definitions = new PropertyDefinitions(); + definitions.addProperty(newProperty("hello", "world")); + definitions.addProperty(newProperty("date", "2010-05-18")); + definitions.addProperty(newProperty("boolean", "true")); + definitions.addProperty(newProperty("falseboolean", "false")); + definitions.addProperty(newProperty("integer", "12345")); + definitions.addProperty(newProperty("array", "one,two,three")); + } + + private Property newProperty(String key, String defaultValue) { + Property prop = mock(Property.class); + when(prop.key()).thenReturn(key); + when(prop.defaultValue()).thenReturn(defaultValue); + return prop; + } + + @Test + public void defaultValuesShouldBeLoadedFromDefinitions() { + Settings settings = new Settings(definitions); + assertThat(settings.getDefaultValue("hello"), is("world")); + } + + @Test + public void testGetDefaultValue() { + Settings settings = new Settings(definitions); + assertThat(settings.getDefaultValue("unknown"), nullValue()); + } + + @Test + public void testGetString() { + Settings settings = new Settings(definitions); + settings.setProperty("hello", "Russia"); + assertThat(settings.getString("hello"), is("Russia")); + } + + @Test + public void testGetDate() { + Settings settings = new Settings(definitions); + assertThat(settings.getDate("date").getDate(), is(18)); + assertThat(settings.getDate("date").getMonth(), is(4)); + } + + @Test + public void testGetDateNotFound() { + Settings settings = new Settings(definitions); + assertThat(settings.getDate("unknown"), CoreMatchers.nullValue()); + } + + @Test + public void testGetArray() { + Settings settings = new Settings(definitions); + String[] array = settings.getStringArray("array"); + assertThat(array.length, is(3)); + assertThat(array[0], is("one")); + assertThat(array[1], is("two")); + assertThat(array[2], is("three")); + } + + @Test + public void testDefaultValueOfGetString() { + Settings settings = new Settings(definitions); + assertThat(settings.getString("hello"), is("world")); + } + + @Test + public void testGetBoolean() { + Settings settings = new Settings(definitions); + assertThat(settings.getBoolean("boolean"), is(true)); + assertThat(settings.getBoolean("falseboolean"), is(false)); + assertThat(settings.getBoolean("unknown"), is(false)); + assertThat(settings.getBoolean("hello"), is(false)); + } + + @Test + public void shouldCreateByIntrospectingComponent() { + Settings settings = Settings.createForComponent(MyComponent.class); + + // property definition has been loaded, ie for default value + assertThat(settings.getDefaultValue("foo"), is("bar")); + } + + @Property(key="foo", name="Foo", defaultValue = "bar") + public static class MyComponent { + + } +} 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 new file mode 100644 index 00000000000..f5a173598c3 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java @@ -0,0 +1,147 @@ +/* + * 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.api.platform; + +import org.junit.Test; +import org.sonar.api.Property; +import org.sonar.api.config.PropertyDefinitions; + +import static junit.framework.Assert.assertTrue; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; + +public class ComponentContainerTest { + + @Test + public void shouldRegisterItself() { + ComponentContainer container = new ComponentContainer(); + assertTrue(container.getComponentByType(ComponentContainer.class) == container); + } + + @Test + public void testStartAndStop() { + ComponentContainer container = new ComponentContainer(); + container.addSingleton(StartableComponent.class); + container.startComponents(); + + assertThat(container.getComponentByType(StartableComponent.class).started, is(true)); + assertThat(container.getComponentByType(StartableComponent.class).stopped, is(false)); + + container.stopComponents(); + assertThat(container.getComponentByType(StartableComponent.class).stopped, is(true)); + } + + @Test + public void testChild() { + ComponentContainer parent = new ComponentContainer(); + parent.startComponents(); + + ComponentContainer child = parent.createChild(); + child.addSingleton(StartableComponent.class); + child.startComponents(); + + assertTrue(child.getParent() == parent); + assertTrue(parent.getChild() == child); + assertTrue(child.getComponentByType(ComponentContainer.class) == child); + assertTrue(parent.getComponentByType(ComponentContainer.class) == parent); + assertThat(child.getComponentByType(StartableComponent.class), notNullValue()); + assertThat(parent.getComponentByType(StartableComponent.class), nullValue()); + + parent.stopComponents(); + } + + @Test + public void testRemoveChild() { + ComponentContainer parent = new ComponentContainer(); + parent.startComponents(); + + ComponentContainer child = parent.createChild(); + assertTrue(parent.getChild() == child); + + parent.removeChild(); + assertThat(parent.getChild(), nullValue()); + } + + @Test + public void shouldForwardStartAndStopToDescendants() { + ComponentContainer grandParent = new ComponentContainer(); + ComponentContainer parent = grandParent.createChild(); + ComponentContainer child = parent.createChild(); + child.addSingleton(StartableComponent.class); + + grandParent.startComponents(); + + StartableComponent component = child.getComponentByType(StartableComponent.class); + assertTrue(component.started); + + parent.stopComponents(); + assertTrue(component.stopped); + } + + @Test + public void shouldDeclareComponentProperties() { + ComponentContainer container = new ComponentContainer(); + container.addSingleton(ComponentWithProperty.class); + + PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); + assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); + assertThat(propertyDefinitions.getProperty("foo").defaultValue(), is("bar")); + } + + @Test + public void shouldDeclareExtensionWithoutAddingIt() { + ComponentContainer container = new ComponentContainer(); + PluginMetadata plugin = mock(PluginMetadata.class); + container.declareExtension(plugin, ComponentWithProperty.class); + + PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); + assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); + assertThat(container.getComponentByType(ComponentWithProperty.class), nullValue()); + } + + @Test + public void shouldDeclareExtensionWhenAdding() { + ComponentContainer container = new ComponentContainer(); + PluginMetadata plugin = mock(PluginMetadata.class); + container.addExtension(plugin, ComponentWithProperty.class); + + PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); + assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); + assertThat(container.getComponentByType(ComponentWithProperty.class), notNullValue()); + } + + public static class StartableComponent { + public boolean started = false, stopped = false; + + public void start() { + started = true; + } + + public void stop() { + stopped = true; + } + } + + @Property(key = "foo", defaultValue = "bar", name = "Foo") + public static class ComponentWithProperty { + + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java index e40cffe871b..257b52b90ab 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java @@ -19,15 +19,14 @@ */ package org.sonar.api.utils; -import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.SystemUtils; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.mortbay.jetty.testing.ServletTester; +import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; import java.io.File; @@ -37,10 +36,8 @@ import java.util.Arrays; import java.util.Properties; import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.not; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; -import static org.junit.Assume.assumeThat; import static org.junit.internal.matchers.StringContains.containsString; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.mock; @@ -161,20 +158,20 @@ public class HttpDownloaderTest { @Test public void downloadBytes() throws URISyntaxException { - byte[] bytes = new HttpDownloader().download(new URI(baseUrl)); + byte[] bytes = new HttpDownloader(new Settings()).download(new URI(baseUrl)); assertThat(bytes.length, greaterThan(10)); } @Test public void downloadPlainText() throws URISyntaxException { - String text = new HttpDownloader().downloadPlainText(new URI(baseUrl), "UTF-8"); + String text = new HttpDownloader(new Settings()).downloadPlainText(new URI(baseUrl), "UTF-8"); assertThat(text.length(), greaterThan(10)); } @Test(expected = SonarException.class) public void failIfServerDown() throws URISyntaxException { // I hope that the port 1 is not used ! - new HttpDownloader().download(new URI("http://localhost:1/unknown")); + new HttpDownloader(new Settings()).download(new URI("http://localhost:1/unknown")); } @Test @@ -184,7 +181,7 @@ public class HttpDownloaderTest { FileUtils.cleanDirectory(toDir); File toFile = new File(toDir, "downloadToFile.txt"); - new HttpDownloader().download(new URI(baseUrl), toFile); + new HttpDownloader(new Settings()).download(new URI(baseUrl), toFile); assertThat(toFile.exists(), is(true)); assertThat(toFile.length(), greaterThan(10l)); } @@ -198,7 +195,7 @@ public class HttpDownloaderTest { try { // I hope that the port 1 is not used ! - new HttpDownloader().download(new URI("http://localhost:1/unknown"), toFile); + new HttpDownloader(new Settings()).download(new URI("http://localhost:1/unknown"), toFile); } catch (SonarException e) { assertThat(toFile.exists(), is(false)); } @@ -209,7 +206,7 @@ public class HttpDownloaderTest { Server server = mock(Server.class); when(server.getVersion()).thenReturn("2.2"); - byte[] bytes = new HttpDownloader(server, new PropertiesConfiguration()).download(new URI(baseUrl)); + byte[] bytes = new HttpDownloader(server, new Settings()).download(new URI(baseUrl)); Properties props = new Properties(); props.load(IOUtils.toInputStream(new String(bytes))); assertThat(props.getProperty("agent"), is("Sonar 2.2")); @@ -217,7 +214,7 @@ public class HttpDownloaderTest { @Test public void followRedirect() throws URISyntaxException { - byte[] bytes = new HttpDownloader().download(new URI(baseUrl + "/redirect/")); + byte[] bytes = new HttpDownloader(new Settings()).download(new URI(baseUrl + "/redirect/")); assertThat(new String(bytes), containsString("count")); } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/IocContainerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/IocContainerTest.java deleted file mode 100644 index abe3578c40c..00000000000 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/IocContainerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.api.utils; - -import static junit.framework.Assert.assertTrue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.core.IsNot.not; -import static org.junit.Assert.assertThat; -import org.junit.Test; -import org.picocontainer.MutablePicoContainer; - -public class IocContainerTest { - - @Test - public void injectContainerAsComponent() { - MutablePicoContainer container = IocContainer.buildPicoContainer(); - assertThat(container.getComponent(IocContainer.class), not(nullValue())); - - // only one instance - assertTrue(container.getComponent(IocContainer.class) == container.getComponent(IocContainer.class)); - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/charts/ChartsServlet.java b/sonar-server/src/main/java/org/sonar/server/charts/ChartsServlet.java index f54967ee5a7..c4e2fda39bb 100644 --- a/sonar-server/src/main/java/org/sonar/server/charts/ChartsServlet.java +++ b/sonar-server/src/main/java/org/sonar/server/charts/ChartsServlet.java @@ -50,7 +50,7 @@ public class ChartsServlet extends HttpServlet { deprecatedDoGet(request, response); } else { - ChartFactory chartFactory = Platform.getInstance().getContainer().getComponent(ChartFactory.class); + ChartFactory chartFactory = Platform.getInstance().getContainer().getComponentByType(ChartFactory.class); Chart chart = chartFactory.getChart(request.getParameter("ck")); if (chart != null) { BufferedImage image = chart.generateImage(getParams(request)); diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationFactory.java b/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationFactory.java deleted file mode 100644 index bc7f086ec6d..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationFactory.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.server.configuration; - -import org.apache.commons.configuration.*; -import org.apache.commons.configuration.interpol.ConfigurationInterpolator; -import org.apache.commons.lang.text.StrLookup; - -import javax.servlet.ServletContextEvent; -import java.io.File; -import java.util.HashMap; - -public final class ConfigurationFactory { - - public ConfigurationFactory() { - allowUsingEnvironmentVariables(); - } - - public Configuration getConfiguration(ServletContextEvent sce) { - CoreConfiguration configuration = new CoreConfiguration(); - configuration.addConfiguration(getConfigurationFromPropertiesFile()); - configuration.addConfiguration(new SystemConfiguration()); - configuration.addConfiguration(new EnvironmentConfiguration()); - configuration.addConfiguration(getDirectoriesConfiguration(sce)); - return configuration; - } - - private void allowUsingEnvironmentVariables() { - ConfigurationInterpolator.registerGlobalLookup("env", new StrLookup() { - @Override - public String lookup(String varName) { - return System.getenv(varName); - } - }); - } - - private Configuration getDirectoriesConfiguration(ServletContextEvent sce) { - MapConfiguration result = new MapConfiguration(new HashMap()); - String webAppDir = autodetectWebappDeployDirectory(sce); - result.setProperty(CoreConfiguration.DEPLOY_DIR, webAppDir); - return result; - } - - protected PropertiesConfiguration getConfigurationFromPropertiesFile(String filename) { - try { - return new PropertiesConfiguration(ConfigurationFactory.class.getResource(filename)); - - } catch (org.apache.commons.configuration.ConfigurationException e) { - throw new ConfigurationException("can not load the file " + filename + " from classpath", e); - } - } - - public PropertiesConfiguration getConfigurationFromPropertiesFile() { - return getConfigurationFromPropertiesFile("/conf/sonar.properties"); - } - - protected String autodetectWebappDeployDirectory(ServletContextEvent sce) { - String webAppPublicDirPath = sce.getServletContext().getRealPath("/deploy/"); - if (webAppPublicDirPath == null) { - throw new ConfigurationException("Web app directory not found : /deploy/"); - } - File file = new File(webAppPublicDirPath); - if (!file.exists()) { - throw new ConfigurationException("Web app directory not found : " + file); - } - return file.toString(); - } - -} diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationLogger.java b/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationLogger.java deleted file mode 100644 index b63d156e787..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/configuration/ConfigurationLogger.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.server.configuration; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Iterator; - -public final class ConfigurationLogger { - - private ConfigurationLogger() { - // only static methods - } - - public static void log(Configuration configuration) { - Logger log = LoggerFactory.getLogger(ConfigurationLogger.class); - if (log.isDebugEnabled()) { - Iterator keys = configuration.getKeys(); - while (keys.hasNext()) { - String key = keys.next(); - String property = getTruncatedProperty(configuration, key); - log.debug("Property: " + key + " is: '" + property + "'"); - } - } - } - - static String getTruncatedProperty(Configuration configuration, String key) { - String property = StringUtils.join(configuration.getStringArray(key), ","); - return StringUtils.abbreviate(property, 100); - } - -} diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/CoreConfiguration.java b/sonar-server/src/main/java/org/sonar/server/configuration/CoreConfiguration.java deleted file mode 100644 index 8e018e52af0..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/configuration/CoreConfiguration.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.server.configuration; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.sonar.api.database.configuration.DatabaseConfiguration; - -public class CoreConfiguration extends CompositeConfiguration { - public static final String DEPLOY_DIR = "sonar.web.deployDir"; - - public DatabaseConfiguration getDatabaseConfiguration() { - int total = getNumberOfConfigurations(); - for (int i = 0; i < total; i++) { - if (getConfiguration(i) instanceof DatabaseConfiguration) { - return (DatabaseConfiguration) getConfiguration(i); - } - } - return null; - } - - public void reload() { - DatabaseConfiguration dbConfig = getDatabaseConfiguration(); - if (dbConfig != null) { - dbConfig.load(); - } - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java b/sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java new file mode 100644 index 00000000000..72b0afb6a8d --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java @@ -0,0 +1,156 @@ +/* + * 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.server.configuration; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.configuration.Property; +import org.sonar.core.config.ConfigurationUtils; +import org.sonar.jpa.session.DatabaseSessionFactory; + +import javax.servlet.ServletContext; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Properties; + +/** + * Load settings from environment, conf/sonar.properties and database + * + * @since 2.12 + */ +public class ServerSettings extends Settings { + + public static final String DEPLOY_DIR = "sonar.web.deployDir"; + + private DatabaseSessionFactory sessionFactory; + private Configuration deprecatedConfiguration; + private File sonarHome; + private File deployDir; + + public ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, ServletContext servletContext) { + super(definitions); + this.deprecatedConfiguration = deprecatedConfiguration; + this.sonarHome = getSonarHome(); + this.deployDir = getDeployDir(servletContext); + load(); + } + + public ServerSettings setSessionFactory(DatabaseSessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + return this; + } + + public ServerSettings load() { + clear(); + setProperty(CoreProperties.SONAR_HOME, sonarHome.getAbsolutePath()); + setProperty(DEPLOY_DIR, deployDir.getAbsolutePath()); + + // order is important + loadDatabaseSettings(); + addEnvironmentVariables(); + addSystemProperties(); + loadPropertiesFile(); + + // update deprecated configuration + ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedConfiguration); + + return this; + } + + private void loadDatabaseSettings() { + if (sessionFactory != null) { + DatabaseSession session = sessionFactory.getSession(); + + // Ugly workaround before the move to myBatis + // Session is not up-to-date when Ruby on Rails inserts new rows in its own transaction. Seems like + // Hibernate keeps a cache... + session.commit(); + List properties = session.createQuery("from " + Property.class.getSimpleName() + " p where p.resourceId is null and p.userId is null").getResultList(); + + for (Property property : properties) { + setProperty(property.getKey(), property.getValue()); + } + } + } + + private void loadPropertiesFile() { + File propertiesFile = new File(sonarHome, "conf/sonar.properties"); + if (!propertiesFile.isFile() || !propertiesFile.exists()) { + throw new IllegalStateException("Properties file does not exist: " + propertiesFile); + } + + try { + Properties p = ConfigurationUtils.openProperties(propertiesFile); + p = ConfigurationUtils.interpolateEnvVariables(p); + addProperties(p); + + } catch (Exception e) { + throw new IllegalStateException("Fail to load configuration file: " + propertiesFile, e); + } + } + + static File getDeployDir(ServletContext servletContext) { + String dirname = servletContext.getRealPath("/deploy/"); + if (dirname == null) { + throw new IllegalArgumentException("Web app directory not found : /deploy/"); + } + File dir = new File(dirname); + if (!dir.exists()) { + throw new IllegalArgumentException("Web app directory does not exist: " + dir); + } + return dir; + } + + static File getSonarHome() { + String home = System.getProperty("sonar.home"); + if (StringUtils.isBlank(home)) { + home = System.getenv("SONAR_HOME"); + if (StringUtils.isBlank(home)) { + Properties warProps = openWarProperties(); + home = warProps.getProperty("sonar.home"); + } + } + + if (StringUtils.isBlank(home)) { + throw new IllegalStateException("Please set location to SONAR_HOME"); + } + + File dir = new File(home); + if (!dir.isDirectory() || !dir.exists()) { + throw new IllegalStateException("SONAR_HOME is not valid: " + home); + } + return dir; + } + + private static Properties openWarProperties() { + try { + InputStream input = ServerSettings.class.getResourceAsStream("/sonar-war.properties"); + return ConfigurationUtils.openInputStream(input); + } catch (IOException e) { + throw new IllegalStateException("Fail to load the file sonar-war.properties", e); + } + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabase.java b/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabase.java index 0543528de6b..cf08eb23786 100644 --- a/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabase.java +++ b/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabase.java @@ -19,10 +19,11 @@ */ package org.sonar.server.database; -import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.apache.derby.drda.NetworkServerControl; import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; import org.sonar.api.utils.Logs; import org.sonar.api.utils.SonarException; @@ -33,6 +34,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; +import java.sql.SQLOutput; import java.util.Properties; public class EmbeddedDatabase { @@ -46,9 +48,9 @@ public class EmbeddedDatabase { private Properties dbProps; private PrintWriter dbLog; - public EmbeddedDatabase(Configuration configuration) { - this.dbHome = autodetectDataDirectory(configuration); - this.dbProps = getDefaultProperties(configuration); + public EmbeddedDatabase(Settings settings) { + this.dbHome = getDataDirectory(settings); + this.dbProps = getDefaultProperties(settings); } public EmbeddedDatabase(File dbHome, Properties dbProps) { @@ -60,10 +62,10 @@ public class EmbeddedDatabase { return dbHome; } - protected File autodetectDataDirectory(Configuration configuration) { - String dirName = configuration.getString(DatabaseProperties.PROP_EMBEDDED_DATA_DIR); - if (dirName == null) { - File sonarHome = new File(configuration.getString(CoreProperties.SONAR_HOME)); + protected File getDataDirectory(Settings settings) { + String dirName = settings.getString(DatabaseProperties.PROP_EMBEDDED_DATA_DIR); + if (StringUtils.isBlank(dirName)) { + File sonarHome = new File(settings.getString(CoreProperties.SONAR_HOME)); if (!sonarHome.isDirectory() || !sonarHome.exists()) { throw new ServerStartException("Sonar home directory does not exist"); } @@ -171,15 +173,15 @@ public class EmbeddedDatabase { } } - public static Properties getDefaultProperties(Configuration configuration) { + public static Properties getDefaultProperties(Settings settings) { Properties props = new Properties(); props.setProperty("derby.drda.startNetworkServer", "true"); - props.setProperty("derby.drda.host", configuration.getString("sonar.derby.drda.host", "localhost")); - props.setProperty("derby.drda.portNumber", configuration.getString("sonar.derby.drda.portNumber", "1527")); - props.setProperty("derby.drda.maxThreads", configuration.getString("sonar.derby.drda.maxThreads", "20")); - props.setProperty("derby.drda.minThreads", configuration.getString("sonar.derby.drda.minThreads", "2")); - props.setProperty("derby.drda.logConnections", configuration.getString("sonar.derby.drda.logConnections", "false")); - props.setProperty("derby.stream.error.logSeverityLevel", configuration.getString("sonar.derby.stream.error.logSeverityLevel", "20000")); + props.setProperty("derby.drda.host", StringUtils.defaultIfBlank(settings.getString("sonar.derby.drda.host"), "localhost")); + props.setProperty("derby.drda.portNumber", StringUtils.defaultIfBlank(settings.getString("sonar.derby.drda.portNumber"), "1527")); + props.setProperty("derby.drda.maxThreads", StringUtils.defaultIfBlank(settings.getString("sonar.derby.drda.maxThreads"), "20")); + props.setProperty("derby.drda.minThreads", StringUtils.defaultIfBlank(settings.getString("sonar.derby.drda.minThreads"), "2")); + props.setProperty("derby.drda.logConnections", StringUtils.defaultIfBlank(settings.getString("sonar.derby.drda.logConnections"), "false")); + props.setProperty("derby.stream.error.logSeverityLevel", StringUtils.defaultIfBlank(settings.getString("sonar.derby.stream.error.logSeverityLevel"), "20000")); props.setProperty("derby.connection.requireAuthentication", "true"); props.setProperty("derby.user." + DEFAULT_USER, DEFAULT_PWD); return props; diff --git a/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabaseFactory.java b/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabaseFactory.java index 92787dee792..b60dd4f7b09 100644 --- a/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabaseFactory.java +++ b/sonar-server/src/main/java/org/sonar/server/database/EmbeddedDatabaseFactory.java @@ -19,21 +19,21 @@ */ package org.sonar.server.database; -import org.apache.commons.configuration.Configuration; +import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; public class EmbeddedDatabaseFactory { - private Configuration configuration; + private Settings settings; private EmbeddedDatabase embeddedDatabase; - public EmbeddedDatabaseFactory(Configuration configuration) { - this.configuration = configuration; + public EmbeddedDatabaseFactory(Settings settings) { + this.settings = settings; } public void start() { - String jdbcUrl = configuration.getString(DatabaseProperties.PROP_URL); - if ((jdbcUrl!=null) && jdbcUrl.startsWith("jdbc:derby://") && jdbcUrl.contains("create=true") && embeddedDatabase==null) { - embeddedDatabase = new EmbeddedDatabase(configuration); + String jdbcUrl = settings.getString(DatabaseProperties.PROP_URL); + if (jdbcUrl != null && jdbcUrl.startsWith("jdbc:derby://") && jdbcUrl.contains("create=true") && embeddedDatabase == null) { + embeddedDatabase = new EmbeddedDatabase(settings); embeddedDatabase.start(); } } diff --git a/sonar-server/src/main/java/org/sonar/server/database/JndiDatabaseConnector.java b/sonar-server/src/main/java/org/sonar/server/database/JndiDatabaseConnector.java index abcb18f9a4c..52d016c0b0e 100644 --- a/sonar-server/src/main/java/org/sonar/server/database/JndiDatabaseConnector.java +++ b/sonar-server/src/main/java/org/sonar/server/database/JndiDatabaseConnector.java @@ -21,7 +21,9 @@ package org.sonar.server.database; import org.apache.commons.configuration.Configuration; import org.apache.commons.dbcp.BasicDataSourceFactory; +import org.apache.commons.lang.StringUtils; import org.hibernate.cfg.Environment; +import org.sonar.api.config.Settings; import org.sonar.api.utils.Logs; import org.sonar.api.utils.SonarException; import org.sonar.jpa.entity.SchemaMigration; @@ -31,13 +33,14 @@ import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Iterator; +import java.util.List; import java.util.Properties; public class JndiDatabaseConnector extends AbstractDatabaseConnector { private DataSource datasource = null; - public JndiDatabaseConnector(Configuration configuration) { + public JndiDatabaseConnector(Settings configuration) { super(configuration, false); } @@ -72,10 +75,9 @@ public class JndiDatabaseConnector extends AbstractDatabaseConnector { try { Logs.INFO.info("Creating JDBC datasource"); Properties properties = new Properties(); - Configuration dsConfig = getConfiguration().subset("sonar.jdbc"); - for (Iterator it = dsConfig.getKeys(); it.hasNext(); ) { - String key = it.next(); - properties.setProperty(key, dsConfig.getString(key)); + List jdbcKeys = configuration.getKeysStartingWith("sonar.jdbc."); + for (String jdbcKey : jdbcKeys) { + properties.setProperty(StringUtils.removeStart(jdbcKey, "sonar.jdbc."), configuration.getString(jdbcKey)); } // This property is required by the Ruby Oracle enhanced adapter. @@ -92,9 +94,6 @@ public class JndiDatabaseConnector extends AbstractDatabaseConnector { public Connection getConnection() throws SQLException { if (datasource != null) { Connection connection = datasource.getConnection(); - if (getTransactionIsolation() != null) { - connection.setTransactionIsolation(getTransactionIsolation()); - } return connection; } return null; diff --git a/sonar-server/src/main/java/org/sonar/server/mavendeployer/MavenRepository.java b/sonar-server/src/main/java/org/sonar/server/mavendeployer/MavenRepository.java index 22455c1a057..bf956a5949e 100644 --- a/sonar-server/src/main/java/org/sonar/server/mavendeployer/MavenRepository.java +++ b/sonar-server/src/main/java/org/sonar/server/mavendeployer/MavenRepository.java @@ -19,10 +19,10 @@ */ package org.sonar.server.mavendeployer; -import org.apache.commons.configuration.Configuration; import org.apache.commons.io.FileUtils; +import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; -import org.sonar.server.configuration.CoreConfiguration; +import org.sonar.server.configuration.ServerSettings; import org.sonar.server.platform.DefaultServerFileSystem; import java.io.File; @@ -34,10 +34,10 @@ public class MavenRepository { private final String serverId; private File rootDir; - public MavenRepository(Configuration configuration, DefaultServerFileSystem fileSystem, Server server) throws IOException { + public MavenRepository(Settings settings, DefaultServerFileSystem fileSystem, Server server) throws IOException { this.installation = fileSystem; this.serverId = server.getId(); - initRootDir(configuration); + initRootDir(settings); } /** @@ -60,8 +60,8 @@ public class MavenRepository { } - private void initRootDir(Configuration configuration) throws IOException { - this.rootDir = new File(configuration.getString(CoreConfiguration.DEPLOY_DIR), "maven"); + private void initRootDir(Settings settings) throws IOException { + this.rootDir = new File(settings.getString(ServerSettings.DEPLOY_DIR), "maven"); File orgDir = new File(rootDir, "/org/"); if (orgDir.exists()) { FileUtils.forceDelete(orgDir); diff --git a/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java b/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java index ae4f45f507a..523ec15aa44 100644 --- a/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java +++ b/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java @@ -19,17 +19,11 @@ */ package org.sonar.server.notifications; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.configuration.Configuration; -import org.sonar.api.ServerComponent; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; +import com.google.common.collect.Sets; +import org.sonar.api.*; +import org.sonar.api.config.Settings; import org.sonar.api.notifications.Notification; import org.sonar.api.notifications.NotificationChannel; import org.sonar.api.notifications.NotificationDispatcher; @@ -38,22 +32,30 @@ import org.sonar.api.utils.TimeProfiler; import org.sonar.core.notifications.DefaultNotificationManager; import org.sonar.jpa.entity.NotificationQueueElement; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.SetMultimap; -import com.google.common.collect.Sets; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * @since 2.10 */ +@org.sonar.api.Properties({ + @Property( + key = NotificationService.PROPERTY_DELAY, + defaultValue = "60", + name = "Delay of notifications, in seconds", + project = false, + global = false) +}) public class NotificationService implements ServerComponent { private static final TimeProfiler TIME_PROFILER = new TimeProfiler(Logs.INFO).setLevelToDebug(); - private static final String DELAY = "sonar.notifications.delay"; - private static final long DELAY_DEFAULT = 60; + public static final String PROPERTY_DELAY = "sonar.notifications.delay"; private ScheduledExecutorService executorService; - private long delay; + private long delayInSeconds; private DefaultNotificationManager manager; private NotificationChannel[] channels; @@ -64,13 +66,13 @@ public class NotificationService implements ServerComponent { /** * Default constructor when no channels. */ - public NotificationService(Configuration configuration, DefaultNotificationManager manager, NotificationDispatcher[] dispatchers) { - this(configuration, manager, dispatchers, new NotificationChannel[0]); + public NotificationService(Settings settings, DefaultNotificationManager manager, NotificationDispatcher[] dispatchers) { + this(settings, manager, dispatchers, new NotificationChannel[0]); Logs.INFO.warn("There is no channels - all notifications would be ignored!"); } - public NotificationService(Configuration configuration, DefaultNotificationManager manager, NotificationDispatcher[] dispatchers, NotificationChannel[] channels) { - delay = configuration.getLong(DELAY, DELAY_DEFAULT); + public NotificationService(Settings settings, DefaultNotificationManager manager, NotificationDispatcher[] dispatchers, NotificationChannel[] channels) { + delayInSeconds = settings.getLong(PROPERTY_DELAY); this.manager = manager; this.channels = channels; this.dispatchers = dispatchers; @@ -82,8 +84,8 @@ public class NotificationService implements ServerComponent { public void run() { processQueue(); } - }, 0, delay, TimeUnit.SECONDS); - Logs.INFO.info("Notification service started (delay {} sec.)", delay); + }, 0, delayInSeconds, TimeUnit.SECONDS); + Logs.INFO.info("Notification service started (delay {} sec.)", delayInSeconds); } public void stop() { diff --git a/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java b/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java index 919217b72e0..a3ea2935404 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java @@ -19,14 +19,14 @@ */ package org.sonar.server.platform; -import org.apache.commons.configuration.Configuration; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; import org.sonar.api.platform.ServerFileSystem; import org.sonar.api.utils.Logs; import org.sonar.jpa.session.DatabaseConnector; -import org.sonar.server.configuration.CoreConfiguration; +import org.sonar.server.configuration.ServerSettings; import java.io.File; import java.io.IOException; @@ -45,11 +45,11 @@ public class DefaultServerFileSystem implements ServerFileSystem { private File deployDir; private File homeDir; - public DefaultServerFileSystem(DatabaseConnector databaseConnector, Configuration configuration) { + public DefaultServerFileSystem(DatabaseConnector databaseConnector, Settings settings) { this.databaseConnector = databaseConnector; - this.homeDir = new File(configuration.getString(CoreProperties.SONAR_HOME)); + this.homeDir = new File(settings.getString(CoreProperties.SONAR_HOME)); - String deployPath = configuration.getString(CoreConfiguration.DEPLOY_DIR); + String deployPath = settings.getString(ServerSettings.DEPLOY_DIR); if (StringUtils.isNotBlank(deployPath)) { this.deployDir = new File(deployPath); } 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 c733a991588..8f65905de3e 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 @@ -19,13 +19,10 @@ */ package org.sonar.server.platform; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.picocontainer.Characteristics; -import org.picocontainer.MutablePicoContainer; +import org.apache.commons.configuration.BaseConfiguration; import org.slf4j.LoggerFactory; import org.sonar.api.Plugins; -import org.sonar.api.database.configuration.DatabaseConfiguration; +import org.sonar.api.platform.ComponentContainer; import org.sonar.api.platform.Server; import org.sonar.api.profiles.AnnotationProfileParser; import org.sonar.api.profiles.XMLProfileParser; @@ -53,8 +50,8 @@ import org.sonar.jpa.session.DatabaseSessionFactory; import org.sonar.jpa.session.DatabaseSessionProvider; import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory; import org.sonar.server.charts.ChartFactory; +import org.sonar.server.configuration.ServerSettings; import org.sonar.server.configuration.Backup; -import org.sonar.server.configuration.ConfigurationLogger; import org.sonar.server.configuration.ProfilesManager; import org.sonar.server.database.EmbeddedDatabaseFactory; import org.sonar.server.database.JndiDatabaseConnector; @@ -72,6 +69,8 @@ import org.sonar.server.ui.CodeColorizers; import org.sonar.server.ui.JRubyI18n; import org.sonar.server.ui.Views; +import javax.servlet.ServletContext; + /** * @since 2.2 */ @@ -79,9 +78,9 @@ public final class Platform { private static final Platform INSTANCE = new Platform(); - private MutablePicoContainer rootContainer;// level 1 : only database connectors - private MutablePicoContainer coreContainer;// level 2 : level 1 + core components - private MutablePicoContainer servicesContainer;// level 3 : level 2 + plugin extensions + core components that depend on plugin extensions + private ComponentContainer rootContainer;// level 1 : only database connectors + private ComponentContainer coreContainer;// level 2 : level 1 + core components + private ComponentContainer servicesContainer;// level 3 : level 2 + plugin extensions + core components that depend on plugin extensions private boolean connected = false; private boolean started = false; @@ -93,10 +92,10 @@ public final class Platform { private Platform() { } - public void init(Configuration conf) { + public void init(ServletContext servletContext) { if (!connected) { try { - startDatabaseConnectors(conf); + startDatabaseConnectors(servletContext); connected = true; } catch (Exception e) { @@ -116,117 +115,117 @@ public final class Platform { } } - private void startDatabaseConnectors(Configuration configuration) { - rootContainer = IocContainer.buildPicoContainer(); - ConfigurationLogger.log(configuration); - - rootContainer.as(Characteristics.CACHE).addComponent(configuration); - rootContainer.as(Characteristics.CACHE).addComponent(EmbeddedDatabaseFactory.class); - rootContainer.as(Characteristics.CACHE).addComponent(JndiDatabaseConnector.class); - rootContainer.as(Characteristics.CACHE).addComponent(DefaultServerUpgradeStatus.class); - rootContainer.start(); - - // Platform is already starting, so it's registered after the container startup + private void startDatabaseConnectors(ServletContext servletContext) { + rootContainer = new ComponentContainer(); + rootContainer.addSingleton(servletContext); + rootContainer.addSingleton(IocContainer.class); // for backward compatibility + rootContainer.addSingleton(new BaseConfiguration()); + rootContainer.addSingleton(ServerSettings.class); + rootContainer.addSingleton(EmbeddedDatabaseFactory.class); + rootContainer.addSingleton(JndiDatabaseConnector.class); + rootContainer.addSingleton(DefaultServerUpgradeStatus.class); + rootContainer.startComponents(); } private boolean isUpToDateDatabase() { - JndiDatabaseConnector databaseConnector = getContainer().getComponent(JndiDatabaseConnector.class); + JndiDatabaseConnector databaseConnector = getContainer().getComponentByType(JndiDatabaseConnector.class); return databaseConnector.isOperational(); } private void startCoreComponents() { - coreContainer = rootContainer.makeChildContainer(); - coreContainer.as(Characteristics.CACHE).addComponent(PluginDeployer.class); - coreContainer.as(Characteristics.CACHE).addComponent(DefaultServerPluginRepository.class); - coreContainer.as(Characteristics.CACHE).addComponent(DefaultServerFileSystem.class); - coreContainer.as(Characteristics.CACHE).addComponent(ThreadLocalDatabaseSessionFactory.class); - coreContainer.as(Characteristics.CACHE).addComponent(HttpDownloader.class); - coreContainer.as(Characteristics.CACHE).addComponent(UpdateCenterClient.class); - coreContainer.as(Characteristics.CACHE).addComponent(UpdateCenterMatrixFactory.class); - coreContainer.as(Characteristics.CACHE).addComponent(PluginDownloader.class); - coreContainer.as(Characteristics.CACHE).addComponent(ServerIdGenerator.class); - coreContainer.as(Characteristics.CACHE).addComponent(ServerImpl.class); - coreContainer.as(Characteristics.NO_CACHE).addComponent(FilterExecutor.class); - coreContainer.as(Characteristics.NO_CACHE).addAdapter(new DatabaseSessionProvider()); - coreContainer.start(); + coreContainer = rootContainer.createChild(); + coreContainer.addSingleton(PluginDeployer.class); + coreContainer.addSingleton(DefaultServerPluginRepository.class); + coreContainer.addSingleton(ServerExtensionInstaller.class); + coreContainer.addSingleton(DefaultServerFileSystem.class); + coreContainer.addSingleton(ThreadLocalDatabaseSessionFactory.class); + coreContainer.addPicoAdapter(new DatabaseSessionProvider()); + coreContainer.startComponents(); - DatabaseConfiguration dbConfiguration = new DatabaseConfiguration(coreContainer.getComponent(DatabaseSessionFactory.class)); - coreContainer.getComponent(CompositeConfiguration.class).addConfiguration(dbConfiguration); + DatabaseSessionFactory sessionFactory = coreContainer.getComponentByType(DatabaseSessionFactory.class); + ServerSettings serverSettings = coreContainer.getComponentByType(ServerSettings.class); + serverSettings.setSessionFactory(sessionFactory); + serverSettings.load(); } /** * plugin extensions + all the components that depend on plugin extensions */ private void startServiceComponents() { - servicesContainer = coreContainer.makeChildContainer(); - - DefaultServerPluginRepository pluginRepository = servicesContainer.getComponent(DefaultServerPluginRepository.class); - pluginRepository.registerExtensions(servicesContainer); + servicesContainer = coreContainer.createChild(); + ServerExtensionInstaller extensionRegistrar = servicesContainer.getComponentByType(ServerExtensionInstaller.class); + extensionRegistrar.registerExtensions(servicesContainer); - servicesContainer.as(Characteristics.CACHE).addComponent(DefaultModelFinder.class); // depends on plugins - servicesContainer.as(Characteristics.CACHE).addComponent(DefaultModelManager.class); - servicesContainer.as(Characteristics.CACHE).addComponent(Plugins.class); - servicesContainer.as(Characteristics.CACHE).addComponent(ChartFactory.class); - servicesContainer.as(Characteristics.CACHE).addComponent(Languages.class); - servicesContainer.as(Characteristics.CACHE).addComponent(Views.class); - servicesContainer.as(Characteristics.CACHE).addComponent(CodeColorizers.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(RulesDao.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(MeasuresDao.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(org.sonar.api.database.daos.MeasuresDao.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(ProfilesDao.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(DaoFacade.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(DefaultRulesManager.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(ProfilesManager.class); - servicesContainer.as(Characteristics.NO_CACHE).addComponent(Backup.class); - servicesContainer.as(Characteristics.CACHE).addComponent(AuthenticatorFactory.class); - servicesContainer.as(Characteristics.CACHE).addComponent(ServerLifecycleNotifier.class); - servicesContainer.as(Characteristics.CACHE).addComponent(AnnotationProfileParser.class); - servicesContainer.as(Characteristics.CACHE).addComponent(XMLProfileParser.class); - servicesContainer.as(Characteristics.CACHE).addComponent(XMLProfileSerializer.class); - servicesContainer.as(Characteristics.CACHE).addComponent(AnnotationRuleParser.class); - servicesContainer.as(Characteristics.CACHE).addComponent(XMLRuleParser.class); - servicesContainer.as(Characteristics.CACHE).addComponent(DefaultRuleFinder.class); - servicesContainer.as(Characteristics.CACHE).addComponent(DefaultMetricFinder.class); - servicesContainer.as(Characteristics.CACHE).addComponent(ProfilesConsole.class); - servicesContainer.as(Characteristics.CACHE).addComponent(RulesConsole.class); - servicesContainer.as(Characteristics.CACHE).addComponent(JRubyI18n.class); - servicesContainer.as(Characteristics.CACHE).addComponent(DefaultUserFinder.class); - servicesContainer.as(Characteristics.CACHE).addComponent(I18nManager.class); - servicesContainer.as(Characteristics.CACHE).addComponent(RuleI18nManager.class); - servicesContainer.as(Characteristics.CACHE).addComponent(GwtI18n.class); + servicesContainer.addSingleton(HttpDownloader.class); + servicesContainer.addSingleton(UpdateCenterClient.class); + servicesContainer.addSingleton(UpdateCenterMatrixFactory.class); + servicesContainer.addSingleton(PluginDownloader.class); + servicesContainer.addSingleton(ServerIdGenerator.class); + servicesContainer.addSingleton(ServerImpl.class); + servicesContainer.addComponent(FilterExecutor.class, false); + servicesContainer.addSingleton(DefaultModelFinder.class); // depends on plugins + servicesContainer.addSingleton(DefaultModelManager.class); + servicesContainer.addSingleton(Plugins.class); + servicesContainer.addSingleton(ChartFactory.class); + servicesContainer.addSingleton(Languages.class); + servicesContainer.addSingleton(Views.class); + servicesContainer.addSingleton(CodeColorizers.class); + servicesContainer.addComponent(RulesDao.class, false); + servicesContainer.addComponent(MeasuresDao.class, false); + servicesContainer.addComponent(org.sonar.api.database.daos.MeasuresDao.class, false); + servicesContainer.addComponent(ProfilesDao.class, false); + servicesContainer.addComponent(DaoFacade.class, false); + servicesContainer.addComponent(DefaultRulesManager.class, false); + servicesContainer.addComponent(ProfilesManager.class, false); + servicesContainer.addComponent(Backup.class, false); + servicesContainer.addSingleton(AuthenticatorFactory.class); + servicesContainer.addSingleton(ServerLifecycleNotifier.class); + servicesContainer.addSingleton(AnnotationProfileParser.class); + servicesContainer.addSingleton(XMLProfileParser.class); + servicesContainer.addSingleton(XMLProfileSerializer.class); + servicesContainer.addSingleton(AnnotationRuleParser.class); + servicesContainer.addSingleton(XMLRuleParser.class); + servicesContainer.addSingleton(DefaultRuleFinder.class); + servicesContainer.addSingleton(DefaultMetricFinder.class); + servicesContainer.addSingleton(ProfilesConsole.class); + servicesContainer.addSingleton(RulesConsole.class); + servicesContainer.addSingleton(JRubyI18n.class); + servicesContainer.addSingleton(DefaultUserFinder.class); + servicesContainer.addSingleton(I18nManager.class); + servicesContainer.addSingleton(RuleI18nManager.class); + servicesContainer.addSingleton(GwtI18n.class); // Notifications - servicesContainer.as(Characteristics.CACHE).addComponent(NotificationService.class); - servicesContainer.as(Characteristics.CACHE).addComponent(DefaultNotificationManager.class); - servicesContainer.as(Characteristics.CACHE).addComponent(ReviewsNotificationManager.class); + servicesContainer.addSingleton(NotificationService.class); + servicesContainer.addSingleton(DefaultNotificationManager.class); + servicesContainer.addSingleton(ReviewsNotificationManager.class); - servicesContainer.start(); + servicesContainer.startComponents(); } private void executeStartupTasks() { - MutablePicoContainer startupContainer = servicesContainer.makeChildContainer(); + ComponentContainer startupContainer = servicesContainer.createChild(); try { - startupContainer.as(Characteristics.CACHE).addComponent(MavenRepository.class); - startupContainer.as(Characteristics.CACHE).addComponent(GwtPublisher.class); - startupContainer.as(Characteristics.CACHE).addComponent(RegisterMetrics.class); - startupContainer.as(Characteristics.CACHE).addComponent(RegisterRules.class); - startupContainer.as(Characteristics.CACHE).addComponent(RegisterProvidedProfiles.class); - startupContainer.as(Characteristics.CACHE).addComponent(EnableProfiles.class); - startupContainer.as(Characteristics.CACHE).addComponent(ActivateDefaultProfiles.class); - startupContainer.as(Characteristics.CACHE).addComponent(JdbcDriverDeployer.class); - startupContainer.as(Characteristics.CACHE).addComponent(ServerMetadataPersister.class); - startupContainer.as(Characteristics.CACHE).addComponent(RegisterQualityModels.class); - startupContainer.as(Characteristics.CACHE).addComponent(DeleteDeprecatedMeasures.class); - startupContainer.as(Characteristics.CACHE).addComponent(GeneratePluginIndex.class); - startupContainer.start(); + startupContainer.addSingleton(MavenRepository.class); + startupContainer.addSingleton(GwtPublisher.class); + startupContainer.addSingleton(RegisterMetrics.class); + startupContainer.addSingleton(RegisterRules.class); + startupContainer.addSingleton(RegisterProvidedProfiles.class); + startupContainer.addSingleton(EnableProfiles.class); + startupContainer.addSingleton(ActivateDefaultProfiles.class); + startupContainer.addSingleton(JdbcDriverDeployer.class); + startupContainer.addSingleton(ServerMetadataPersister.class); + startupContainer.addSingleton(RegisterQualityModels.class); + startupContainer.addSingleton(DeleteDeprecatedMeasures.class); + startupContainer.addSingleton(GeneratePluginIndex.class); + startupContainer.startComponents(); - startupContainer.getComponent(ServerLifecycleNotifier.class).notifyStart(); + startupContainer.getComponentByType(ServerLifecycleNotifier.class).notifyStart(); } finally { - startupContainer.stop(); - servicesContainer.removeChildContainer(startupContainer); - startupContainer = null; - servicesContainer.getComponent(DatabaseSessionFactory.class).clear(); + startupContainer.stopComponents(); + servicesContainer.removeChild(); + servicesContainer.getComponentByType(DatabaseSessionFactory.class).clear(); } } @@ -234,7 +233,7 @@ public final class Platform { if (rootContainer != null) { try { TimeProfiler profiler = new TimeProfiler().start("Stop sonar"); - rootContainer.stop(); + rootContainer.stopComponents(); rootContainer = null; connected = false; started = false; @@ -245,7 +244,7 @@ public final class Platform { } } - public MutablePicoContainer getContainer() { + public ComponentContainer getContainer() { if (servicesContainer != null) { return servicesContainer; } @@ -256,7 +255,7 @@ public final class Platform { } public Object getComponent(Object key) { - return getContainer().getComponent(key); + return getContainer().getComponentByKey(key); } /** diff --git a/sonar-server/src/main/java/org/sonar/server/platform/PlatformLifecycleListener.java b/sonar-server/src/main/java/org/sonar/server/platform/PlatformLifecycleListener.java index 22d798048c1..526e4f68239 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/PlatformLifecycleListener.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/PlatformLifecycleListener.java @@ -19,17 +19,13 @@ */ package org.sonar.server.platform; -import org.apache.commons.configuration.Configuration; -import org.sonar.server.configuration.ConfigurationFactory; - import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public final class PlatformLifecycleListener implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { - Configuration configuration = new ConfigurationFactory().getConfiguration(event); - Platform.getInstance().init(configuration); + Platform.getInstance().init(event.getServletContext()); Platform.getInstance().start(); } diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/DefaultServerPluginRepository.java b/sonar-server/src/main/java/org/sonar/server/plugins/DefaultServerPluginRepository.java index 73defaa30d4..864b8a06a0b 100644 --- a/sonar-server/src/main/java/org/sonar/server/plugins/DefaultServerPluginRepository.java +++ b/sonar-server/src/main/java/org/sonar/server/plugins/DefaultServerPluginRepository.java @@ -20,16 +20,15 @@ package org.sonar.server.plugins; import com.google.common.collect.Sets; -import org.picocontainer.Characteristics; -import org.picocontainer.MutablePicoContainer; import org.slf4j.LoggerFactory; -import org.sonar.api.*; +import org.sonar.api.Plugin; +import org.sonar.api.Properties; +import org.sonar.api.Property; import org.sonar.api.platform.PluginMetadata; import org.sonar.api.platform.ServerPluginRepository; import org.sonar.core.plugins.PluginClassloaders; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Set; @@ -49,7 +48,8 @@ public class DefaultServerPluginRepository implements ServerPluginRepository { } public void start() { - pluginsByKey = classloaders.init(deployer.getMetadata()); + Collection metadata = deployer.getMetadata(); + pluginsByKey = classloaders.init(metadata); } public void stop() { @@ -117,55 +117,4 @@ public class DefaultServerPluginRepository implements ServerPluginRepository { return deployer.getMetadata(pluginKey); } - public void registerExtensions(MutablePicoContainer container) { - registerExtensions(container, getPlugins()); - } - - void registerExtensions(MutablePicoContainer container, Collection plugins) { - for (Plugin plugin : plugins) { - container.as(Characteristics.CACHE).addComponent(plugin); - for (Object extension : plugin.getExtensions()) { - installExtension(container, extension, true); - } - } - installExtensionProviders(container); - } - - void installExtensionProviders(MutablePicoContainer container) { - List providers = container.getComponents(ExtensionProvider.class); - for (ExtensionProvider provider : providers) { - Object obj = provider.provide(); - if (obj != null) { - if (obj instanceof Iterable) { - for (Object extension : (Iterable) obj) { - installExtension(container, extension, false); - } - } else { - installExtension(container, obj, false); - } - } - } - } - - void installExtension(MutablePicoContainer container, Object extension, boolean acceptProvider) { - if (isType(extension, ServerExtension.class)) { - if (!acceptProvider && (isType(extension, ExtensionProvider.class) || extension instanceof ExtensionProvider)) { - LoggerFactory.getLogger(getClass()).error("ExtensionProvider can not include providers itself: " + extension); - } else { - container.as(Characteristics.CACHE).addComponent(getExtensionKey(extension), extension); - } - } - } - - static boolean isType(Object extension, Class extensionClass) { - Class clazz = (extension instanceof Class ? (Class) extension : extension.getClass()); - return extensionClass.isAssignableFrom(clazz); - } - - static Object getExtensionKey(Object component) { - if (component instanceof Class) { - return component; - } - return component.getClass().getCanonicalName() + "-" + component.toString(); - } } diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java b/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java new file mode 100644 index 00000000000..cf672d08c04 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java @@ -0,0 +1,101 @@ +/* + * 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.server.plugins; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Maps; +import org.slf4j.LoggerFactory; +import org.sonar.api.Extension; +import org.sonar.api.ExtensionProvider; +import org.sonar.api.Plugin; +import org.sonar.api.ServerExtension; +import org.sonar.api.platform.ComponentContainer; +import org.sonar.api.platform.PluginMetadata; +import org.sonar.api.platform.PluginRepository; + +import java.util.Map; + +public class ServerExtensionInstaller { + private PluginRepository pluginRepository; + + public ServerExtensionInstaller(PluginRepository pluginRepository) { + this.pluginRepository = pluginRepository; + } + + public void registerExtensions(ComponentContainer container) { + ListMultimap installedExtensionsByPlugin = ArrayListMultimap.create(); + + for (PluginMetadata pluginMetadata : pluginRepository.getMetadata()) { + Plugin plugin = pluginRepository.getPlugin(pluginMetadata.getKey()); + container.addExtension(pluginMetadata, plugin); + + for (Object extension : plugin.getExtensions()) { + if (installExtension(container, pluginMetadata, extension, true) != null) { + installedExtensionsByPlugin.put(pluginMetadata, extension); + } else { + container.declareExtension(pluginMetadata, extension); + } + } + } + for (Map.Entry entry : installedExtensionsByPlugin.entries()) { + PluginMetadata plugin = entry.getKey(); + Object extension = entry.getValue(); + if (isExtensionProvider(extension)) { + ExtensionProvider provider = (ExtensionProvider) container.getComponentByKey(extension); + installProvider(container, plugin, provider); + } + } + } + + private void installProvider(ComponentContainer container, PluginMetadata plugin, ExtensionProvider provider) { + Object obj = provider.provide(); + if (obj != null) { + if (obj instanceof Iterable) { + for (Object ext : (Iterable) obj) { + installExtension(container, plugin, ext, false); + } + } else { + installExtension(container, plugin, obj, false); + } + } + } + + Object installExtension(ComponentContainer container, PluginMetadata pluginMetadata, Object extension, boolean acceptProvider) { + if (isType(extension, ServerExtension.class)) { + if (!acceptProvider && isExtensionProvider(extension)) { + LoggerFactory.getLogger(getClass()).error("ExtensionProvider can not include providers itself: " + extension); + } else { + container.addExtension(pluginMetadata, extension); + return extension; + } + } + return null; + } + + static boolean isExtensionProvider(Object extension) { + return isType(extension, ExtensionProvider.class) || extension instanceof ExtensionProvider; + } + + static boolean isType(Object extension, Class extensionClass) { + Class clazz = (extension instanceof Class ? (Class) extension : extension.getClass()); + return extensionClass.isAssignableFrom(clazz); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java b/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java index 1dca1b380ea..83068721c6c 100644 --- a/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java +++ b/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java @@ -44,7 +44,7 @@ public class StaticResourcesServlet extends HttpServlet { String pluginKey = getPluginKey(request); String resource = getResourcePath(request); - DefaultServerPluginRepository pluginRepository = Platform.getInstance().getContainer().getComponent(DefaultServerPluginRepository.class); + DefaultServerPluginRepository pluginRepository = Platform.getInstance().getContainer().getComponentByType(DefaultServerPluginRepository.class); ClassLoader classLoader = pluginRepository.getClassloader(pluginKey); if (classLoader == null) { LOG.error("Plugin not found: " + pluginKey); diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java b/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java index 7dbcc8543d1..32a7ae076b3 100644 --- a/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java +++ b/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java @@ -19,10 +19,12 @@ */ package org.sonar.server.plugins; -import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; import org.slf4j.LoggerFactory; +import org.sonar.api.Properties; +import org.sonar.api.Property; import org.sonar.api.ServerComponent; +import org.sonar.api.config.Settings; import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.Logs; import org.sonar.updatecenter.common.UpdateCenter; @@ -32,17 +34,32 @@ import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Date; -import java.util.Properties; + /** * HTTP client to load data from the remote update center hosted at http://update.sonarsource.org. * * @since 2.4 */ +@Properties({ + @Property( + key = "sonar.updatecenter.activate", + defaultValue = "true", + name = "Enable Update Center", + project = false, + global = false, // hidden from UI + category = "Update Center"), + @Property( + key = UpdateCenterClient.URL_PROPERTY, + defaultValue = "http://update.sonarsource.org/update-center.properties", + name = "Update Center URL", + project = false, + global = false, // hidden from UI + category = "Update Center") +}) public class UpdateCenterClient implements ServerComponent { public static final String URL_PROPERTY = "sonar.updatecenter.url"; - public static final String DEFAULT_URL = "http://update.sonarsource.org/update-center.properties"; public static final int PERIOD_IN_MILLISECONDS = 60 * 60 * 1000; private URI uri; @@ -59,8 +76,8 @@ public class UpdateCenterClient implements ServerComponent { Logs.INFO.info("Update center: " + uri + " (" + downloader.getProxySynthesis(uri) + ")"); } - public UpdateCenterClient(HttpDownloader downloader, Configuration configuration) throws URISyntaxException { - this(downloader, new URI(configuration.getString(URL_PROPERTY, DEFAULT_URL))); + public UpdateCenterClient(HttpDownloader downloader, Settings configuration) throws URISyntaxException { + this(downloader, new URI(configuration.getString(URL_PROPERTY))); } public UpdateCenter getCenter() { @@ -88,7 +105,7 @@ public class UpdateCenterClient implements ServerComponent { try { input = downloader.openStream(uri); if (input != null) { - Properties properties = new Properties(); + java.util.Properties properties = new java.util.Properties(); properties.load(input); return UpdateCenterDeserializer.fromProperties(properties); } diff --git a/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java b/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java index fd7fb4a501d..f61f2bc1b73 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java @@ -19,17 +19,17 @@ */ package org.sonar.server.startup; -import org.apache.commons.configuration.Configuration; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.config.Settings; import org.sonar.api.utils.Logs; import org.sonar.api.utils.SonarException; import org.sonar.api.utils.TimeProfiler; import org.sonar.api.utils.ZipUtils; import org.sonar.api.web.GwtExtension; -import org.sonar.server.configuration.CoreConfiguration; +import org.sonar.server.configuration.ServerSettings; import java.io.File; import java.io.IOException; @@ -41,13 +41,13 @@ import java.util.zip.ZipEntry; public class GwtPublisher { private static final Logger LOG = LoggerFactory.getLogger(GwtPublisher.class); - private Configuration configuration; + private Settings settings; private GwtExtension[] extensions = null; private File outputDir = null; - public GwtPublisher(GwtExtension[] extensions, Configuration configuration) { + public GwtPublisher(GwtExtension[] extensions, Settings settings) { this.extensions = extensions; - this.configuration = configuration; + this.settings = settings; } protected GwtPublisher(GwtExtension[] extensions, File outputDir) { @@ -62,7 +62,7 @@ public class GwtPublisher { TimeProfiler profiler = new TimeProfiler().start("Deploy GWT plugins"); try { cleanDirectory(); - this.outputDir = new File(configuration.getString(CoreConfiguration.DEPLOY_DIR), "gwt"); + this.outputDir = new File(settings.getString(ServerSettings.DEPLOY_DIR), "gwt"); Logs.INFO.debug("publish {} GWT extensions to {}", extensions.length, outputDir); publish(); diff --git a/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorFactory.java b/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorFactory.java index ed42799fd97..17038c09756 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorFactory.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/AuthenticatorFactory.java @@ -19,12 +19,12 @@ */ package org.sonar.server.ui; -import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; import org.sonar.api.ServerComponent; +import org.sonar.api.config.Settings; import org.sonar.api.security.LoginPasswordAuthenticator; public class AuthenticatorFactory implements ServerComponent { @@ -37,17 +37,17 @@ public class AuthenticatorFactory implements ServerComponent { private boolean ignoreStartupFailure; private LoginPasswordAuthenticator[] authenticators; - public AuthenticatorFactory(Configuration configuration, LoginPasswordAuthenticator[] authenticators) { - classname = configuration.getString(CoreProperties.CORE_AUTHENTICATOR_CLASS); - ignoreStartupFailure = configuration.getBoolean(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, false); + public AuthenticatorFactory(Settings settings, LoginPasswordAuthenticator[] authenticators) { + classname = settings.getString(CoreProperties.CORE_AUTHENTICATOR_CLASS); + ignoreStartupFailure = settings.getBoolean(CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE); this.authenticators = authenticators; } /** * This constructor is used when there aren't any authentication plugins. */ - public AuthenticatorFactory(Configuration configuration) { - this(configuration, null); + public AuthenticatorFactory(Settings settings) { + this(settings, null); } /** diff --git a/sonar-server/src/main/java/org/sonar/server/ui/DatabaseSessionFilter.java b/sonar-server/src/main/java/org/sonar/server/ui/DatabaseSessionFilter.java index 1c7d6f43123..7b8db246bce 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/DatabaseSessionFilter.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/DatabaseSessionFilter.java @@ -33,7 +33,7 @@ public class DatabaseSessionFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); - DatabaseSessionFactory sessionFactory = Platform.getInstance().getContainer().getComponent(DatabaseSessionFactory.class); + DatabaseSessionFactory sessionFactory = Platform.getInstance().getContainer().getComponentByType(DatabaseSessionFactory.class); if (sessionFactory != null) { sessionFactory.clear(); } diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index bb8d0d3b99b..59598488060 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -20,9 +20,10 @@ package org.sonar.server.ui; import org.apache.commons.configuration.Configuration; -import org.picocontainer.PicoContainer; import org.slf4j.LoggerFactory; -import org.sonar.api.Property; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; +import org.sonar.api.platform.ComponentContainer; import org.sonar.api.platform.PluginMetadata; import org.sonar.api.platform.PluginRepository; import org.sonar.api.profiles.ProfileExporter; @@ -36,8 +37,8 @@ import org.sonar.core.i18n.RuleI18nManager; import org.sonar.jpa.dialect.Dialect; import org.sonar.jpa.session.DatabaseConnector; import org.sonar.markdown.Markdown; +import org.sonar.server.configuration.ServerSettings; import org.sonar.server.configuration.Backup; -import org.sonar.server.configuration.CoreConfiguration; import org.sonar.server.configuration.ProfilesManager; import org.sonar.server.filters.Filter; import org.sonar.server.filters.FilterExecutor; @@ -66,52 +67,51 @@ public final class JRubyFacade { } public FilterResult executeFilter(Filter filter) { - return getContainer().getComponent(FilterExecutor.class).execute(filter); + return getContainer().getComponentByType(FilterExecutor.class).execute(filter); } // UPDATE CENTER ------------------------------------------------------------ public void downloadPlugin(String pluginKey, String pluginVersion) { - getContainer().getComponent(PluginDownloader.class).download(pluginKey, Version.create(pluginVersion)); + getContainer().getComponentByType(PluginDownloader.class).download(pluginKey, Version.create(pluginVersion)); } public void cancelPluginDownloads() { - getContainer().getComponent(PluginDownloader.class).cancelDownloads(); + getContainer().getComponentByType(PluginDownloader.class).cancelDownloads(); } public List getPluginDownloads() { - return getContainer().getComponent(PluginDownloader.class).getDownloads(); + return getContainer().getComponentByType(PluginDownloader.class).getDownloads(); } public void uninstallPlugin(String pluginKey) { - getContainer().getComponent(PluginDeployer.class).uninstall(pluginKey); + getContainer().getComponentByType(PluginDeployer.class).uninstall(pluginKey); } public void cancelPluginUninstalls() { - getContainer().getComponent(PluginDeployer.class).cancelUninstalls(); + getContainer().getComponentByType(PluginDeployer.class).cancelUninstalls(); } public List getPluginUninstalls() { - return getContainer().getComponent(PluginDeployer.class).getUninstalls(); + return getContainer().getComponentByType(PluginDeployer.class).getUninstalls(); } public UpdateCenterMatrix getUpdateCenterMatrix(boolean forceReload) { - return getContainer().getComponent(UpdateCenterMatrixFactory.class).getMatrix(forceReload); + return getContainer().getComponentByType(UpdateCenterMatrixFactory.class).getMatrix(forceReload); } // PLUGINS ------------------------------------------------------------------ - public Property[] getPluginProperties(PluginMetadata metadata) { - PluginRepository repository = getContainer().getComponent(PluginRepository.class); - return repository.getProperties(repository.getPlugin(metadata.getKey())); + public PropertyDefinitions getPropertyDefinitions() { + return getContainer().getComponentByType(PropertyDefinitions.class); } public boolean hasPlugin(String key) { - return getContainer().getComponent(PluginRepository.class).getPlugin(key) != null; + return getContainer().getComponentByType(PluginRepository.class).getPlugin(key) != null; } public Collection getPluginsMetadata() { - return getContainer().getComponent(PluginRepository.class).getMetadata(); + return getContainer().getComponentByType(PluginRepository.class).getMetadata(); } @@ -119,7 +119,7 @@ public final class JRubyFacade { public String colorizeCode(String code, String language) { try { - return getContainer().getComponent(CodeColorizers.class).toHtml(code, language); + return getContainer().getComponentByType(CodeColorizers.class).toHtml(code, language); } catch (Exception e) { LoggerFactory.getLogger(getClass()).error("Can not highlight the code, language= " + language, e); @@ -133,89 +133,89 @@ public final class JRubyFacade { public List> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage) { - return getContainer().getComponent(Views.class).getWidgets(resourceScope, resourceQualifier, resourceLanguage); + return getContainer().getComponentByType(Views.class).getWidgets(resourceScope, resourceQualifier, resourceLanguage); } public List> getWidgets() { - return getContainer().getComponent(Views.class).getWidgets(); + return getContainer().getComponentByType(Views.class).getWidgets(); } public ViewProxy getWidget(String id) { - return getContainer().getComponent(Views.class).getWidget(id); + return getContainer().getComponentByType(Views.class).getWidget(id); } public List> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage) { - return getContainer().getComponent(Views.class).getPages(section, resourceScope, resourceQualifier, resourceLanguage); + return getContainer().getComponentByType(Views.class).getPages(section, resourceScope, resourceQualifier, resourceLanguage); } public List> getResourceTabs() { - return getContainer().getComponent(Views.class).getPages(NavigationSection.RESOURCE_TAB, null, null, null); + return getContainer().getComponentByType(Views.class).getPages(NavigationSection.RESOURCE_TAB, null, null, null); } public List> getResourceTabs(String scope, String qualifier, String language) { - return getContainer().getComponent(Views.class).getPages(NavigationSection.RESOURCE_TAB, scope, qualifier, language); + return getContainer().getComponentByType(Views.class).getPages(NavigationSection.RESOURCE_TAB, scope, qualifier, language); } public List> getResourceTabsForMetric(String scope, String qualifier, String language, String metric) { - return getContainer().getComponent(Views.class).getPagesForMetric(NavigationSection.RESOURCE_TAB, scope, qualifier, language, metric); + return getContainer().getComponentByType(Views.class).getPagesForMetric(NavigationSection.RESOURCE_TAB, scope, qualifier, language, metric); } public ViewProxy getPage(String id) { - return getContainer().getComponent(Views.class).getPage(id); + return getContainer().getComponentByType(Views.class).getPage(id); } public Collection getRubyRailsWebservices() { - return getContainer().getComponents(RubyRailsWebservice.class); + return getContainer().getComponentsByType(RubyRailsWebservice.class); } public Collection getLanguages() { - return getContainer().getComponents(Language.class); + return getContainer().getComponentsByType(Language.class); } public Dialect getDialect() { - return getContainer().getComponent(DatabaseConnector.class).getDialect(); + return getContainer().getComponentByType(DatabaseConnector.class).getDialect(); } /* PROFILES CONSOLE : RULES AND METRIC THRESHOLDS */ public List getRuleRepositories() { - return getContainer().getComponent(RulesConsole.class).getRepositories(); + return getContainer().getComponentByType(RulesConsole.class).getRepositories(); } public RuleRepository getRuleRepository(String repositoryKey) { - return getContainer().getComponent(RulesConsole.class).getRepository(repositoryKey); + return getContainer().getComponentByType(RulesConsole.class).getRepository(repositoryKey); } public Set getRuleRepositoriesByLanguage(String languageKey) { - return getContainer().getComponent(RulesConsole.class).getRepositoriesByLanguage(languageKey); + return getContainer().getComponentByType(RulesConsole.class).getRepositoriesByLanguage(languageKey); } public String backupProfile(int profileId) { - return getContainer().getComponent(ProfilesConsole.class).backupProfile(profileId); + return getContainer().getComponentByType(ProfilesConsole.class).backupProfile(profileId); } public ValidationMessages restoreProfile(String xmlBackup) { - return getContainer().getComponent(ProfilesConsole.class).restoreProfile(xmlBackup); + return getContainer().getComponentByType(ProfilesConsole.class).restoreProfile(xmlBackup); } public List getProfileExportersForLanguage(String language) { - return getContainer().getComponent(ProfilesConsole.class).getProfileExportersForLanguage(language); + return getContainer().getComponentByType(ProfilesConsole.class).getProfileExportersForLanguage(language); } public List getProfileImportersForLanguage(String language) { - return getContainer().getComponent(ProfilesConsole.class).getProfileImportersForLanguage(language); + return getContainer().getComponentByType(ProfilesConsole.class).getProfileImportersForLanguage(language); } public String exportProfile(int profileId, String exporterKey) { - return getContainer().getComponent(ProfilesConsole.class).exportProfile(profileId, exporterKey); + return getContainer().getComponentByType(ProfilesConsole.class).exportProfile(profileId, exporterKey); } public ValidationMessages importProfile(String profileName, String language, String importerKey, String fileContent) { - return getContainer().getComponent(ProfilesConsole.class).importProfile(profileName, language, importerKey, fileContent); + return getContainer().getComponentByType(ProfilesConsole.class).importProfile(profileName, language, importerKey, fileContent); } public String getProfileExporterMimeType(String exporterKey) { - return getContainer().getComponent(ProfilesConsole.class).getProfileExporter(exporterKey).getMimeType(); + return getContainer().getComponentByType(ProfilesConsole.class).getProfileExporter(exporterKey).getMimeType(); } public void renameProfile(int profileId, String newProfileName) { @@ -256,36 +256,40 @@ public final class JRubyFacade { } public List