]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6732 CE must load Settings from DB for each worker
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Wed, 16 Mar 2016 12:42:31 +0000 (13:42 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 21 Mar 2016 15:44:05 +0000 (16:44 +0100)
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

16 files changed:
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/ce/settings/ComputeEngineSettings.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/settings/ThreadLocalSettings.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/ce/settings/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
server/sonar-server/src/main/java/org/sonar/server/computation/taskprocessor/report/ReportTaskProcessor.java
server/sonar-server/src/main/java/org/sonar/server/platform/PersistentSettings.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java
server/sonar-server/src/main/java/org/sonar/server/platform/WebServerSettings.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SetDefaultTemplateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/platform/PersistentSettingsTest.java
server/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java
sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java

index 3d16c5fbeb7a6e041b8f0331bb33eedcaa80b7cc..2ba3b853a777e246ad91d85c5e79139131f08291 100644 (file)
@@ -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 (file)
index 0000000..a11eeef
--- /dev/null
@@ -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.
+ *
+ * <p>
+ * 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()}).
+ * </p>
+ */
+public class ComputeEngineSettings extends Settings implements ThreadLocalSettings, ServerSettings {
+  private final ServerSettings defaultDelegate;
+  private final ThreadLocal<ServerSettings> 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<String, String> 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<String, String> 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<String, String> 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<String> 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<String, String> 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<String, String> 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<String, String> 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 (file)
index 0000000..a525606
--- /dev/null
@@ -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 (file)
index 0000000..a8e314b
--- /dev/null
@@ -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;
index b4fdae4b08a4865441c60bc77dbaf8c4b2eca0cf..f0e6d0e62bdb7e53c75b88d5b2e8ef8fb9192c7e 100644 (file)
@@ -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<ComputeEngineContainer> populator) {
-    super(createContainer(requireNonNull(parent)));
+    super(createContainer(requireNonNull(parent)), parent.getComponentByType(PropertyDefinitions.class));
 
     populateContainer(requireNonNull(populator));
     startComponents();
index 82ed25a8009f0a603e5a7c29591086e70f889e80..1c79df7d1cbde90da4460d900844e8e0a128013b 100644 (file)
@@ -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,
index 22c5f350121f8c91e9b7858fb63e03f8a73e3aa2..912177763db54a84ed93413c49f4813445d0b0f7 100644 (file)
@@ -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();
     }
   }
index a79556610c0b3107865354ec94431fa4cdcc7948..bf344e1788c9eb3075ca6a5744e0014c5d2c20b0 100644 (file)
@@ -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<String, String> 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<String, String> getProperties() {
-    return settings.getProperties();
+    return serverSettings.getProperties();
   }
 
   public Settings getSettings() {
-    return settings;
+    return serverSettings.getSettings();
   }
 
   public List<PropertyDto> getGlobalProperties() {
index 7f569052a8616595ec1caa7e1edcd2f6bfdc2e8d..36ea147376367bcfdd8765019d34df3856c20191 100644 (file)
  */
 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) :
- * <ol>
- * <li>general settings persisted in database</li>
- * <li>file $SONAR_HOME/conf/sonar.properties</li>
- * <li>environment variables</li>
- * <li>system properties</li>
- * </ol>
- *
- * @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<String, String> databaseProperties);
+
+  Settings getSettings();
+
+  /**
+   * @see Settings#getString(String)
+   */
+  String getString(String key);
 
-  private final Properties properties;
+  /**
+   * @see Settings#getProperties()
+   */
+  Map<String, String> getProperties();
 
-  public ServerSettings(PropertyDefinitions definitions, Properties properties) {
-    super(definitions);
-    this.properties = properties;
-    load(Collections.<String, String>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<String, String> databaseProperties) {
-    return load(databaseProperties);
-  }
+  /**
+   * @see Settings#setProperty(String, String)
+   */
+  Settings setProperty(String key, String value);
 
-  private ServerSettings load(Map<String, String> 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<String, String> 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 (file)
index 0000000..7a74f92
--- /dev/null
@@ -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) :
+ * <ol>
+ * <li>general settings persisted in database</li>
+ * <li>file $SONAR_HOME/conf/sonar.properties</li>
+ * <li>environment variables</li>
+ * <li>system properties</li>
+ * </ol>
+ *
+ * @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.<String, String>emptyMap());
+    // Secret key is loaded from conf/sonar.properties
+    getEncryption().setPathToSecretKey(getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
+  }
+
+  @Override
+  public ServerSettings activateDatabaseSettings(Map<String, String> databaseProperties) {
+    return load(databaseProperties);
+  }
+
+  @Override
+  public Settings getSettings() {
+    return this;
+  }
+
+  private ServerSettings load(Map<String, String> databaseSettings) {
+    clear();
+
+    // order is important : the last override the first
+    addProperties(databaseSettings);
+    addProperties(properties);
+
+    return this;
+  }
+}
index 9a3b3ae3fe5aae09f7c4dc181738f00402342786..ae0469e3237a7a0ab3f9d924998d9c39fe55e2e5 100644 (file)
@@ -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,
index b9ecd37cdecb0801167fceb13821091324ea09cb..b9440a088169f63989312f0bb811ca38539f551e 100644 (file)
@@ -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");
index 7be68d5fed3a8c63f7db0c8152b26ad09d10e28d..0dc3f8c1d4e5969e49e0c6395f2a968bd0c9d9bc 100644 (file)
@@ -45,7 +45,7 @@ public class PersistentSettingsTest {
   public void init() {
     dao = mock(PropertiesDao.class);
 
-    settings = new ServerSettings(
+    settings = new WebServerSettings(
       new PropertyDefinitions(),
       new Properties());
   }
index 35fdfd6ddc6c495082059e34be97fa5228e7029e..7e2aef096798167ecbafb7a9281f6cf6842e085d 100644 (file)
@@ -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
index 5162e6a8d409e0143ccad8b79e21e864bd0f2dcc..597311caf07f0bfecc7f1dafd80d012e9402c996 100644 (file)
@@ -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);
   }
index 3beb0a9aceda9d3fe9ad71d8e8d34b513f9ca1a5..fc5100ce2c4d607afc99ef942fb5f955898c061b 100644 (file)
@@ -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() {