From 37e32de9c0fb62c14bff9f750332324d542c9cee Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 16 Mar 2016 13:42:31 +0100 Subject: [PATCH] SONAR-6732 CE must load Settings from DB for each worker renamed ServerSettings to WebServerSettings and extract from it a ServerSetting interface to be able to easily provide separte implementations for Web Server and CE) CE Server implementation is called ComputeEngineSettings which supports loading up to date Settings for a specific worker using delegation and a ThreadLocal --- .../container/ComputeEngineContainerImpl.java | 6 +- .../ce/settings/ComputeEngineSettings.java | 333 ++++++++++++++++++ .../ce/settings/ThreadLocalSettings.java | 34 ++ .../org/sonar/ce/settings/package-info.java | 23 ++ .../container/ComputeEngineContainerImpl.java | 3 +- ...ReportComputeEngineContainerPopulator.java | 7 +- .../report/ReportTaskProcessor.java | 14 +- .../server/platform/PersistentSettings.java | 22 +- .../sonar/server/platform/ServerSettings.java | 70 ++-- .../server/platform/WebServerSettings.java | 72 ++++ .../platformlevel/PlatformLevel1.java | 4 +- .../SetDefaultTemplateActionTest.java | 4 +- .../platform/PersistentSettingsTest.java | 2 +- .../server/platform/ServerSettingsTest.java | 4 +- .../core/platform/ComponentContainer.java | 7 +- .../java/org/sonar/api/config/Settings.java | 6 +- 16 files changed, 546 insertions(+), 65 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/ce/settings/ComputeEngineSettings.java create mode 100644 server/sonar-server/src/main/java/org/sonar/ce/settings/ThreadLocalSettings.java create mode 100644 server/sonar-server/src/main/java/org/sonar/ce/settings/package-info.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/WebServerSettings.java diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 3d16c5fbeb7..2ba3b853a77 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -37,6 +37,7 @@ import org.sonar.api.utils.System2; import org.sonar.api.utils.UriReader; import org.sonar.ce.es.EsIndexerEnabler; import org.sonar.ce.property.CePropertyDefinitions; +import org.sonar.ce.settings.ComputeEngineSettings; import org.sonar.core.component.DefaultResourceTypes; import org.sonar.core.config.CorePropertyDefinitions; import org.sonar.core.i18n.DefaultI18n; @@ -106,7 +107,6 @@ import org.sonar.server.platform.ServerIdGenerator; import org.sonar.server.platform.ServerImpl; import org.sonar.server.platform.ServerLifecycleNotifier; import org.sonar.server.platform.ServerLogging; -import org.sonar.server.platform.ServerSettings; import org.sonar.server.platform.TempFolderProvider; import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.ServerExtensionInstaller; @@ -139,8 +139,8 @@ import org.sonarqube.ws.Rules; public class ComputeEngineContainerImpl implements ComputeEngineContainer { private static final Object[] LEVEL_1_COMPONENTS = new Object[] { + ComputeEngineSettings.class, new SonarQubeVersionProvider(), - ServerSettings.class, ServerImpl.class, UuidFactoryImpl.INSTANCE, // no EmbeddedDatabaseFactory.class, creating H2 DB if responsibility of WebServer @@ -160,7 +160,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { // DB DbClient.class, DaoModule.class, - // MigrationStepModule.class, DB maintenance, responsibility of Web Server + // MigrationStepModule.class, DB maintenance, responsibility of Web Server // Elasticsearch EsSearchModule.class, diff --git a/server/sonar-server/src/main/java/org/sonar/ce/settings/ComputeEngineSettings.java b/server/sonar-server/src/main/java/org/sonar/ce/settings/ComputeEngineSettings.java new file mode 100644 index 00000000000..a11eeef1829 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/ce/settings/ComputeEngineSettings.java @@ -0,0 +1,333 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.ce.settings; + +import com.google.common.base.Objects; +import com.google.common.collect.Maps; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Encryption; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; +import org.sonar.core.platform.ComponentContainer; +import org.sonar.db.DbClient; +import org.sonar.db.property.PropertyDto; +import org.sonar.server.platform.ServerSettings; + +import static com.google.common.base.Preconditions.checkState; + +/** + * This class implements ServerSettings and extends Settings so that it can be injected in any component depending upon + * either ServerSettings or Settings. + * + *

+ * In order to honor both Settings and ThreadLocalSettings contracts, none of the code inherited from the Settings super + * class is actually used. Every public method of Settings is override and their implementation is delegated to + * an inner object which can either be the default one or one specific to the current Thread. Selected of the inner + * object will depend on whether the current Thread made use of method {@link #load()} or not. This approach also greatly + * simplifies delegation code (see {@link #currentDelegate()}). + *

+ */ +public class ComputeEngineSettings extends Settings implements ThreadLocalSettings, ServerSettings { + private final ServerSettings defaultDelegate; + private final ThreadLocal threadLocalDelegate = new ThreadLocal<>(); + + private final Properties rootProperties; + private final ComponentContainer componentContainer; + // we can't get injected with DBClient because it creates a circular dependency + private volatile DbClient dbClient; + + public ComputeEngineSettings(PropertyDefinitions definitions, Properties rootProperties, ComponentContainer componentContainer) { + super(definitions); + this.rootProperties = rootProperties; + this.componentContainer = componentContainer; + + this.defaultDelegate = new ServerSettingsImpl(definitions, rootProperties); + } + + @Override + public void load() { + checkState( + this.threadLocalDelegate.get() == null, + "loadLocal called twice for Thread '%' or state wasn't cleared last time it was used", + Thread.currentThread().getName()); + this.threadLocalDelegate.set(loadServerSettings()); + } + + @Override + public void remove() { + this.threadLocalDelegate.remove(); + } + + private ServerSettings loadServerSettings() { + ServerSettings res = new ServerSettingsImpl(this.definitions, this.rootProperties); + Map databaseProperties = Maps.newHashMap(); + for (PropertyDto property : getDbClient().propertiesDao().selectGlobalProperties()) { + databaseProperties.put(property.getKey(), property.getValue()); + } + res.activateDatabaseSettings(databaseProperties); + return res; + } + + private DbClient getDbClient() { + if (dbClient == null) { + this.dbClient = componentContainer.getComponentByType(DbClient.class); + } + return dbClient; + } + + private ServerSettings currentDelegate() { + return Objects.firstNonNull(threadLocalDelegate.get(), defaultDelegate); + } + + private Settings currentSettings() { + return currentDelegate().getSettings(); + } + + @Override + public ServerSettings activateDatabaseSettings(Map databaseProperties) { + checkState(threadLocalDelegate.get() == null, "activateDatabaseSettings must not be called from a Worker"); + + return defaultDelegate.activateDatabaseSettings(databaseProperties); + } + + private static final class ServerSettingsImpl extends Settings implements ServerSettings { + + private final Properties rootProperties; + + public ServerSettingsImpl(PropertyDefinitions definitions, Properties rootProperties) { + super(definitions); + this.rootProperties = rootProperties; + addProperties(rootProperties); + // Secret key is loaded from conf/sonar.properties + getEncryption().setPathToSecretKey(getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); + } + + @Override + public ServerSettings activateDatabaseSettings(Map databaseProperties) { + clear(); + + // order is important : the last override the first + addProperties(databaseProperties); + addProperties(rootProperties); + + return this; + } + + @Override + public Settings getSettings() { + return this; + } + } + + @Override + public Settings getSettings() { + return this; + } + + @Override + public Encryption getEncryption() { + return currentSettings().getEncryption(); + } + + @Override + @CheckForNull + public String getDefaultValue(String key) { + return currentSettings().getDefaultValue(key); + } + + @Override + public boolean hasKey(String key) { + return currentSettings().hasKey(key); + } + + @Override + public boolean hasDefaultValue(String key) { + return currentSettings().hasDefaultValue(key); + } + + @Override + @CheckForNull + public String getString(String key) { + return currentDelegate().getString(key); + } + + @Override + public boolean getBoolean(String key) { + return currentSettings().getBoolean(key); + } + + @Override + public int getInt(String key) { + return currentSettings().getInt(key); + } + + @Override + public long getLong(String key) { + return currentSettings().getLong(key); + } + + @Override + @CheckForNull + public Date getDate(String key) { + return currentSettings().getDate(key); + } + + @Override + @CheckForNull + public Date getDateTime(String key) { + return currentSettings().getDateTime(key); + } + + @Override + @CheckForNull + public Float getFloat(String key) { + return currentSettings().getFloat(key); + } + + @Override + @CheckForNull + public Double getDouble(String key) { + return currentSettings().getDouble(key); + } + + @Override + public String[] getStringArray(String key) { + return currentSettings().getStringArray(key); + } + + @Override + public String[] getStringLines(String key) { + return currentSettings().getStringLines(key); + } + + @Override + public String[] getStringArrayBySeparator(String key, String separator) { + return currentSettings().getStringArrayBySeparator(key, separator); + } + + @Override + public List getKeysStartingWith(String prefix) { + return currentSettings().getKeysStartingWith(prefix); + } + + @Override + public Settings appendProperty(String key, String value) { + return currentSettings().appendProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable String[] values) { + return currentSettings().setProperty(key, values); + } + + @Override + public Settings setProperty(String key, @Nullable String value) { + return currentSettings().setProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable Boolean value) { + return currentSettings().setProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable Integer value) { + return currentSettings().setProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable Long value) { + return currentSettings().setProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable Double value) { + return currentSettings().setProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable Float value) { + return currentSettings().setProperty(key, value); + } + + @Override + public Settings setProperty(String key, @Nullable Date date) { + return currentSettings().setProperty(key, date); + } + + @Override + public Settings addProperties(Map props) { + return currentSettings().addProperties(props); + } + + @Override + public Settings addProperties(Properties props) { + return currentSettings().addProperties(props); + } + + @Override + @Deprecated + public Settings addSystemProperties() { + return currentSettings().addSystemProperties(); + } + + @Override + @Deprecated + public Settings addEnvironmentVariables() { + return currentSettings().addEnvironmentVariables(); + } + + @Override + public Settings setProperties(Map props) { + return currentSettings().setProperties(props); + } + + @Override + public Settings setProperty(String key, @Nullable Date date, boolean includeTime) { + return currentSettings().setProperty(key, date, includeTime); + } + + @Override + public Settings removeProperty(String key) { + return currentSettings().removeProperty(key); + } + + @Override + public Settings clear() { + return currentSettings().clear(); + } + + @Override + public Map getProperties() { + return currentSettings().getProperties(); + } + + @Override + public PropertyDefinitions getDefinitions() { + return currentSettings().getDefinitions(); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/ce/settings/ThreadLocalSettings.java b/server/sonar-server/src/main/java/org/sonar/ce/settings/ThreadLocalSettings.java new file mode 100644 index 00000000000..a525606b16d --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/ce/settings/ThreadLocalSettings.java @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.ce.settings; + +public interface ThreadLocalSettings { + /** + * Loads up-to-date Settings specific to the current thread. + * + * @throws IllegalStateException if the current thread already has specific Settings + */ + void load(); + + /** + * Clears the Settings specific to the current thread (if any). + */ + void remove(); +} diff --git a/server/sonar-server/src/main/java/org/sonar/ce/settings/package-info.java b/server/sonar-server/src/main/java/org/sonar/ce/settings/package-info.java new file mode 100644 index 00000000000..a8e314bea56 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/ce/settings/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.ce.settings; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java index b4fdae4b08a..f0e6d0e62bd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java @@ -31,6 +31,7 @@ import org.picocontainer.behaviors.OptInCaching; import org.picocontainer.lifecycle.ReflectionLifecycleStrategy; import org.picocontainer.monitors.ComponentMonitorHelper; import org.picocontainer.monitors.NullComponentMonitor; +import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.core.platform.ComponentContainer; @@ -47,7 +48,7 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co private static final Logger LOG = Loggers.get(ComputeEngineContainerImpl.class); public ComputeEngineContainerImpl(ComponentContainer parent, ContainerPopulator populator) { - super(createContainer(requireNonNull(parent))); + super(createContainer(requireNonNull(parent)), parent.getComponentByType(PropertyDefinitions.class)); populateContainer(requireNonNull(populator)); startComponents(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java index 82ed25a8009..1c79df7d1cb 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java @@ -22,6 +22,7 @@ package org.sonar.server.computation.container; import java.util.Arrays; import java.util.List; import javax.annotation.Nullable; +import org.sonar.ce.queue.CeTask; import org.sonar.core.issue.tracking.Tracker; import org.sonar.core.platform.ContainerPopulator; import org.sonar.server.computation.analysis.AnalysisMetadataHolderImpl; @@ -81,7 +82,6 @@ import org.sonar.server.computation.qualitymodel.NewQualityModelMeasuresVisitor; import org.sonar.server.computation.qualitymodel.QualityModelMeasuresVisitor; import org.sonar.server.computation.qualitymodel.RatingSettings; import org.sonar.server.computation.qualityprofile.ActiveRulesHolderImpl; -import org.sonar.ce.queue.CeTask; import org.sonar.server.computation.scm.ScmInfoRepositoryImpl; import org.sonar.server.computation.source.LastCommitVisitor; import org.sonar.server.computation.source.SourceHashRepositoryImpl; @@ -121,6 +121,8 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop private static List componentClasses() { return Arrays.asList( ComputationStepExecutor.class, + + // File System new ComputationTempFolderProvider(), MetricModule.class, @@ -172,7 +174,8 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop TestErrorRule.class, SkippedTestRule.class, - // order is important: RuleTypeCopier must be the first one. And DebtAggregator must be before NewDebtAggregator (new debt requires debt) + // order is important: RuleTypeCopier must be the first one. And DebtAggregator must be before NewDebtAggregator (new debt requires + // debt) RuleTypeCopier.class, RuleTagsCopier.class, DebtCalculator.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/report/ReportTaskProcessor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/report/ReportTaskProcessor.java index 22c5f350121..912177763db 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/report/ReportTaskProcessor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/report/ReportTaskProcessor.java @@ -22,14 +22,15 @@ package org.sonar.server.computation.taskprocessor.report; import java.util.Collections; import java.util.Set; import javax.annotation.CheckForNull; +import org.sonar.ce.queue.CeTask; +import org.sonar.ce.queue.CeTaskResult; +import org.sonar.ce.settings.ThreadLocalSettings; +import org.sonar.ce.taskprocessor.CeTaskProcessor; import org.sonar.core.platform.ComponentContainer; import org.sonar.db.ce.CeTaskTypes; import org.sonar.server.computation.container.ComputeEngineContainer; import org.sonar.server.computation.container.ContainerFactory; -import org.sonar.ce.queue.CeTask; -import org.sonar.ce.queue.CeTaskResult; import org.sonar.server.computation.step.ComputationStepExecutor; -import org.sonar.ce.taskprocessor.CeTaskProcessor; import org.sonar.server.computation.taskprocessor.TaskResultHolder; import org.sonar.server.devcockpit.DevCockpitBridge; @@ -68,10 +69,17 @@ public class ReportTaskProcessor implements CeTaskProcessor { @Override public CeTaskResult process(CeTask task) { ComputeEngineContainer ceContainer = containerFactory.create(serverContainer, task, devCockpitBridge); + ThreadLocalSettings ceSettings = null; try { + ceSettings = ceContainer.getComponentByType(ThreadLocalSettings.class); + ceSettings.load(); + ceContainer.getComponentByType(ComputationStepExecutor.class).execute(); return ceContainer.getComponentByType(TaskResultHolder.class).getResult(); } finally { + if (ceSettings != null) { + ceSettings.remove(); + } ceContainer.cleanup(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java b/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java index a79556610c0..bf344e1788c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java @@ -34,11 +34,11 @@ import java.util.Map; */ public class PersistentSettings implements Startable { private final PropertiesDao propertiesDao; - private final ServerSettings settings; + private final ServerSettings serverSettings; - public PersistentSettings(PropertiesDao propertiesDao, ServerSettings settings) { + public PersistentSettings(PropertiesDao propertiesDao, ServerSettings serverSettings) { this.propertiesDao = propertiesDao; - this.settings = settings; + this.serverSettings = serverSettings; } @Override @@ -47,7 +47,7 @@ public class PersistentSettings implements Startable { for (PropertyDto property : getGlobalProperties()) { databaseProperties.put(property.getKey(), property.getValue()); } - settings.activateDatabaseSettings(databaseProperties); + serverSettings.activateDatabaseSettings(databaseProperties); } @Override @@ -56,39 +56,39 @@ public class PersistentSettings implements Startable { } public PersistentSettings saveProperty(String key, @Nullable String value) { - settings.setProperty(key, value); + serverSettings.setProperty(key, value); propertiesDao.insertProperty(new PropertyDto().setKey(key).setValue(value)); return this; } public PersistentSettings deleteProperty(String key) { - settings.removeProperty(key); + serverSettings.removeProperty(key); propertiesDao.deleteGlobalProperty(key); return this; } public PersistentSettings deleteProperties() { - settings.clear(); + serverSettings.clear(); propertiesDao.deleteGlobalProperties(); return this; } public PersistentSettings saveProperties(Map properties) { - settings.addProperties(properties); + serverSettings.addProperties(properties); propertiesDao.insertGlobalProperties(properties); return this; } public String getString(String key) { - return settings.getString(key); + return serverSettings.getString(key); } public Map getProperties() { - return settings.getProperties(); + return serverSettings.getProperties(); } public Settings getSettings() { - return settings; + return serverSettings.getSettings(); } public List getGlobalProperties() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java index 7f569052a86..36ea1473763 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java @@ -19,48 +19,50 @@ */ package org.sonar.server.platform; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.PropertyDefinitions; -import org.sonar.api.config.Settings; - -import java.util.Collections; import java.util.Map; -import java.util.Properties; +import org.sonar.api.config.Settings; /** - * Load settings in the following order (the last override the first) : - *
    - *
  1. general settings persisted in database
  2. - *
  3. file $SONAR_HOME/conf/sonar.properties
  4. - *
  5. environment variables
  6. - *
  7. system properties
  8. - *
- * - * @since 2.12 + * Defines some of the methods of {@link Settings} plus some specific to load db properties on the server side + * (see {@link PersistentSettings}). */ -public class ServerSettings extends Settings { +public interface ServerSettings { + ServerSettings activateDatabaseSettings(Map databaseProperties); + + Settings getSettings(); + + /** + * @see Settings#getString(String) + */ + String getString(String key); - private final Properties properties; + /** + * @see Settings#getProperties() + */ + Map getProperties(); - public ServerSettings(PropertyDefinitions definitions, Properties properties) { - super(definitions); - this.properties = properties; - load(Collections.emptyMap()); - // Secret key is loaded from conf/sonar.properties - getEncryption().setPathToSecretKey(getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); - } + /** + * @see Settings#hasKey(String) + */ + boolean hasKey(String foo); - public ServerSettings activateDatabaseSettings(Map databaseProperties) { - return load(databaseProperties); - } + /** + * @see Settings#setProperty(String, String) + */ + Settings setProperty(String key, String value); - private ServerSettings load(Map databaseSettings) { - clear(); + /** + * @see Settings#removeProperty(String) + */ + Settings removeProperty(String key); - // order is important : the last override the first - addProperties(databaseSettings); - addProperties(properties); + /** + * @see Settings#clear() + */ + Settings clear(); - return this; - } + /** + * @see Settings#addProperties(Map) + */ + Settings addProperties(Map properties); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/WebServerSettings.java b/server/sonar-server/src/main/java/org/sonar/server/platform/WebServerSettings.java new file mode 100644 index 00000000000..7a74f92318c --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/WebServerSettings.java @@ -0,0 +1,72 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform; + +import org.sonar.api.CoreProperties; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; + +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +/** + * Load settings in the following order (the last override the first) : + *
    + *
  1. general settings persisted in database
  2. + *
  3. file $SONAR_HOME/conf/sonar.properties
  4. + *
  5. environment variables
  6. + *
  7. system properties
  8. + *
+ * + * @since 2.12 + */ +public class WebServerSettings extends Settings implements ServerSettings { + + private final Properties properties; + + public WebServerSettings(PropertyDefinitions definitions, Properties properties) { + super(definitions); + this.properties = properties; + load(Collections.emptyMap()); + // Secret key is loaded from conf/sonar.properties + getEncryption().setPathToSecretKey(getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); + } + + @Override + public ServerSettings activateDatabaseSettings(Map databaseProperties) { + return load(databaseProperties); + } + + @Override + public Settings getSettings() { + return this; + } + + private ServerSettings load(Map databaseSettings) { + clear(); + + // order is important : the last override the first + addProperties(databaseSettings); + addProperties(properties); + + return this; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java index 9a3b3ae3fe5..ae0469e3237 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java @@ -42,7 +42,7 @@ import org.sonar.server.platform.DatabaseServerCompatibility; import org.sonar.server.platform.DefaultServerFileSystem; import org.sonar.server.platform.Platform; import org.sonar.server.platform.ServerImpl; -import org.sonar.server.platform.ServerSettings; +import org.sonar.server.platform.WebServerSettings; import org.sonar.server.platform.TempFolderProvider; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.ruby.PlatformRackBridge; @@ -70,7 +70,7 @@ public class PlatformLevel1 extends PlatformLevel { add( new SonarQubeVersionProvider(), ProcessCommandWrapperImpl.class, - ServerSettings.class, + WebServerSettings.class, ServerImpl.class, UuidFactoryImpl.INSTANCE, EmbeddedDatabaseFactory.class, diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SetDefaultTemplateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SetDefaultTemplateActionTest.java index b9ecd37cdec..b9440a08816 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SetDefaultTemplateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SetDefaultTemplateActionTest.java @@ -44,7 +44,7 @@ import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.i18n.I18nRule; import org.sonar.server.permission.ws.PermissionDependenciesFinder; import org.sonar.server.platform.PersistentSettings; -import org.sonar.server.platform.ServerSettings; +import org.sonar.server.platform.WebServerSettings; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.usergroups.ws.UserGroupFinder; import org.sonar.server.ws.TestRequest; @@ -82,7 +82,7 @@ public class SetDefaultTemplateActionTest { @Before public void setUp() { DbClient dbClient = db.getDbClient(); - persistentSettings = new PersistentSettings(dbClient.propertiesDao(), new ServerSettings(new PropertyDefinitions(), new Properties())); + persistentSettings = new PersistentSettings(dbClient.propertiesDao(), new WebServerSettings(new PropertyDefinitions(), new Properties())); persistentSettings.saveProperty(DEFAULT_TEMPLATE_PROPERTY, "any-template-uuid"); persistentSettings.saveProperty(defaultRootQualifierTemplateProperty(PROJECT), "any-template-uuid"); persistentSettings.saveProperty(defaultRootQualifierTemplateProperty(VIEW), "any-view-template-uuid"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java index 7be68d5fed3..0dc3f8c1d4e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java @@ -45,7 +45,7 @@ public class PersistentSettingsTest { public void init() { dao = mock(PropertiesDao.class); - settings = new ServerSettings( + settings = new WebServerSettings( new PropertyDefinitions(), new Properties()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java index 35fdfd6ddc6..7e2aef09679 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java @@ -33,7 +33,7 @@ public class ServerSettingsTest { Properties properties; - ServerSettings settings; + WebServerSettings settings; @Before public void before() { @@ -41,7 +41,7 @@ public class ServerSettingsTest { properties.put("hello", "world"); properties.put("in_file", "true"); properties.put("ServerSettingsTestEnv", "in_file"); - settings = new ServerSettings(new PropertyDefinitions(), properties); + settings = new WebServerSettings(new PropertyDefinitions(), properties); } @Test diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java index 5162e6a8d40..597311caf07 100644 --- a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java +++ b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java @@ -90,10 +90,15 @@ public class ComponentContainer implements ContainerPopulator.Container { } protected ComponentContainer(MutablePicoContainer picoContainer) { + this(picoContainer, new PropertyDefinitions()); + } + + protected ComponentContainer(MutablePicoContainer picoContainer, PropertyDefinitions propertyDefinitions) { + requireNonNull(propertyDefinitions, "PropertyDefinitions can not be null"); this.parent = null; this.pico = picoContainer; this.componentKeys = new ComponentKeys(); - propertyDefinitions = new PropertyDefinitions(); + this.propertyDefinitions = propertyDefinitions; addSingleton(propertyDefinitions); addSingleton(this); } 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 index 3beb0a9aced..fc5100ce2c4 100644 --- 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 @@ -110,9 +110,9 @@ public class Settings { * @since 3.1 */ public Settings(Settings other) { - this.properties = Maps.newHashMap(other.properties); - this.definitions = other.definitions; - this.encryption = other.encryption; + this.properties = Maps.newHashMap(other.getProperties()); + this.definitions = other.getDefinitions(); + this.encryption = other.getEncryption(); } public Encryption getEncryption() { -- 2.39.5