aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src/main
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-06-09 15:16:10 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2014-06-10 12:36:10 +0200
commitda92c49827337bd34fbf077d5d74c9fbfb8ec287 (patch)
tree8e53db0de00d84dc712ad69904105430e65f8e6f /sonar-batch/src/main
parent5d0730e2be1a25c186049a3255c50772818ae4c1 (diff)
downloadsonarqube-da92c49827337bd34fbf077d5d74c9fbfb8ec287.tar.gz
sonarqube-da92c49827337bd34fbf077d5d74c9fbfb8ec287.zip
Separate bootstrap settings and task settings
Diffstat (limited to 'sonar-batch/src/main')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java26
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java58
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java44
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapProperties.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java83
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java25
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java33
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskProperties.java36
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java5
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/UserProperties.java62
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java56
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/DeprecatedProjectReactorBuilder.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java35
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorBuilder.java12
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java5
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/settings/DefaultSettingsReferential.java79
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/settings/SettingsReferential.java43
17 files changed, 386 insertions, 236 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java
index b524b5b6acf..4415122c3f6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java
@@ -39,8 +39,8 @@ public class AnalysisMode implements BatchComponent {
private boolean incremental;
private int previewReadTimeoutSec;
- public AnalysisMode(BootstrapSettings bootstrapSettings) {
- init(bootstrapSettings);
+ public AnalysisMode(BootstrapProperties bootstrapProps) {
+ init(bootstrapProps);
}
public boolean isPreview() {
@@ -51,13 +51,13 @@ public class AnalysisMode implements BatchComponent {
return incremental;
}
- private void init(BootstrapSettings bootstrapSettings) {
- if (bootstrapSettings.properties().containsKey(CoreProperties.DRY_RUN)) {
+ private void init(BootstrapProperties bootstrapProps) {
+ if (bootstrapProps.properties().containsKey(CoreProperties.DRY_RUN)) {
LOG.warn(MessageFormat.format("Property {0} is deprecated. Please use {1} instead.", CoreProperties.DRY_RUN, CoreProperties.ANALYSIS_MODE));
- preview = "true".equals(bootstrapSettings.property(CoreProperties.DRY_RUN));
+ preview = "true".equals(bootstrapProps.property(CoreProperties.DRY_RUN));
incremental = false;
} else {
- String mode = bootstrapSettings.property(CoreProperties.ANALYSIS_MODE);
+ String mode = bootstrapProps.property(CoreProperties.ANALYSIS_MODE);
preview = CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode);
incremental = CoreProperties.ANALYSIS_MODE_INCREMENTAL.equals(mode);
}
@@ -68,19 +68,19 @@ public class AnalysisMode implements BatchComponent {
}
// To stay compatible with plugins that use the old property to check mode
if (incremental || preview) {
- bootstrapSettings.properties().put(CoreProperties.DRY_RUN, "true");
- previewReadTimeoutSec = loadPreviewReadTimeout(bootstrapSettings);
+ bootstrapProps.properties().put(CoreProperties.DRY_RUN, "true");
+ previewReadTimeoutSec = loadPreviewReadTimeout(bootstrapProps);
}
}
// SONAR-4488 Allow to increase preview read timeout
- private int loadPreviewReadTimeout(BootstrapSettings bootstrapSettings) {
+ private int loadPreviewReadTimeout(BootstrapProperties bootstrapProps) {
int readTimeoutSec;
- if (bootstrapSettings.property(CoreProperties.DRY_RUN_READ_TIMEOUT_SEC) != null) {
+ if (bootstrapProps.property(CoreProperties.DRY_RUN_READ_TIMEOUT_SEC) != null) {
LOG.warn("Property {} is deprecated. Please use {} instead.", CoreProperties.DRY_RUN_READ_TIMEOUT_SEC, CoreProperties.PREVIEW_READ_TIMEOUT_SEC);
- readTimeoutSec = Integer.parseInt(bootstrapSettings.property(CoreProperties.DRY_RUN_READ_TIMEOUT_SEC));
- } else if (bootstrapSettings.property(CoreProperties.PREVIEW_READ_TIMEOUT_SEC) != null) {
- readTimeoutSec = Integer.parseInt(bootstrapSettings.property(CoreProperties.PREVIEW_READ_TIMEOUT_SEC));
+ readTimeoutSec = Integer.parseInt(bootstrapProps.property(CoreProperties.DRY_RUN_READ_TIMEOUT_SEC));
+ } else if (bootstrapProps.property(CoreProperties.PREVIEW_READ_TIMEOUT_SEC) != null) {
+ readTimeoutSec = Integer.parseInt(bootstrapProps.property(CoreProperties.PREVIEW_READ_TIMEOUT_SEC));
} else {
readTimeoutSec = DEFAULT_PREVIEW_READ_TIMEOUT_SEC;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java
index 63f0824663c..b818a602361 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java
@@ -19,39 +19,40 @@
*/
package org.sonar.batch.bootstrap;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
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.batch.bootstrap.ProjectReactor;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
-import org.sonar.api.utils.SonarException;
+import org.sonar.api.utils.MessageException;
+import org.sonar.batch.settings.SettingsReferential;
import javax.annotation.Nullable;
-import java.util.List;
+
import java.util.Map;
public class BatchSettings extends Settings {
- public static final String BATCH_BOOTSTRAP_PROPERTIES_URL = "/batch_bootstrap/properties";
+
+ private static final Logger LOG = LoggerFactory.getLogger(BatchSettings.class);
+
private Configuration deprecatedConfiguration;
- private boolean preview;
- private final BootstrapSettings bootstrapSettings;
- private final ServerClient client;
+ private final BootstrapProperties bootstrapProps;
+ private final SettingsReferential settingsReferential;
private final AnalysisMode mode;
private Map<String, String> savedProperties;
- public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions,
- ServerClient client, Configuration deprecatedConfiguration, AnalysisMode mode) {
+ public BatchSettings(BootstrapProperties bootstrapProps, PropertyDefinitions propertyDefinitions,
+ SettingsReferential settingsReferential, Configuration deprecatedConfiguration, AnalysisMode mode) {
super(propertyDefinitions);
this.mode = mode;
- getEncryption().setPathToSecretKey(bootstrapSettings.property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
- this.bootstrapSettings = bootstrapSettings;
- this.client = client;
+ getEncryption().setPathToSecretKey(bootstrapProps.property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
+ this.bootstrapProps = bootstrapProps;
+ this.settingsReferential = settingsReferential;
this.deprecatedConfiguration = deprecatedConfiguration;
init(null);
}
@@ -59,26 +60,24 @@ public class BatchSettings extends Settings {
public void init(@Nullable ProjectReactor reactor) {
savedProperties = this.getProperties();
- this.preview = mode.isPreview();
if (reactor != null) {
- LoggerFactory.getLogger(BatchSettings.class).info("Load project settings");
- String branch = bootstrapSettings.property(CoreProperties.PROJECT_BRANCH_PROPERTY);
+ LOG.info("Load project settings");
+
+ String branch = reactor.getRoot().getProperties().getProperty(CoreProperties.PROJECT_BRANCH_PROPERTY);
String projectKey = reactor.getRoot().getKey();
if (StringUtils.isNotBlank(branch)) {
projectKey = String.format("%s:%s", projectKey, branch);
}
downloadSettings(projectKey);
} else {
- LoggerFactory.getLogger(BatchSettings.class).info("Load batch settings");
+ LOG.info("Load global settings");
downloadSettings(null);
}
- addProperties(bootstrapSettings.properties());
+ addProperties(bootstrapProps.properties());
if (reactor != null) {
addProperties(reactor.getRoot().getProperties());
}
- properties.putAll(System.getenv());
- addProperties(System.getProperties());
}
/**
@@ -89,21 +88,10 @@ public class BatchSettings extends Settings {
}
private void downloadSettings(@Nullable String projectKey) {
- String url;
if (StringUtils.isNotBlank(projectKey)) {
- url = BATCH_BOOTSTRAP_PROPERTIES_URL + "?project=" + projectKey + "&dryRun=" + preview;
+ addProperties(settingsReferential.projectSettings(projectKey));
} else {
- url = BATCH_BOOTSTRAP_PROPERTIES_URL + "?dryRun=" + preview;
- }
- String jsonText = client.request(url);
-
- List<Map<String, String>> json = new Gson().fromJson(jsonText, new TypeToken<List<Map<String, String>>>() {
- }.getType());
-
- for (Map<String, String> jsonProperty : json) {
- String key = jsonProperty.get("k");
- String value = jsonProperty.get("v");
- setProperty(key, value);
+ addProperties(settingsReferential.globalSettings());
}
}
@@ -124,8 +112,8 @@ public class BatchSettings extends Settings {
@Override
protected void doOnGetProperties(String key) {
- if (preview && key.endsWith(".secured") && !key.contains(".license")) {
- throw new SonarException("Access to the secured property '" + key
+ if (mode.isPreview() && key.endsWith(".secured") && !key.contains(".license")) {
+ throw MessageException.of("Access to the secured property '" + key
+ "' is not possible in preview mode. The SonarQube plugin which requires this property must be deactivated in preview mode.");
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
index c2076bc83f3..feffc2f6ede 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
@@ -19,8 +19,6 @@
*/
package org.sonar.batch.bootstrap;
-import org.sonar.core.cluster.NullQueue;
-
import org.apache.commons.configuration.PropertiesConfiguration;
import org.sonar.api.Plugin;
import org.sonar.api.config.EmailSettings;
@@ -31,7 +29,6 @@ import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.UriReader;
import org.sonar.api.utils.internal.TempFolderCleaner;
-import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.components.PastMeasuresLoader;
import org.sonar.batch.components.PastSnapshotFinder;
import org.sonar.batch.components.PastSnapshotFinderByDate;
@@ -39,8 +36,9 @@ import org.sonar.batch.components.PastSnapshotFinderByDays;
import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis;
import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion;
import org.sonar.batch.components.PastSnapshotFinderByVersion;
-import org.sonar.batch.scan.DeprecatedProjectReactorBuilder;
-import org.sonar.batch.scan.ProjectReactorBuilder;
+import org.sonar.batch.settings.DefaultSettingsReferential;
+import org.sonar.batch.settings.SettingsReferential;
+import org.sonar.core.cluster.NullQueue;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.DefaultI18n;
import org.sonar.core.i18n.RuleI18nManager;
@@ -64,13 +62,16 @@ import java.util.Map;
public class BootstrapContainer extends ComponentContainer {
- private BootstrapContainer() {
+ private final Map<String, String> bootstrapProperties;
+
+ private BootstrapContainer(Map<String, String> bootstrapProperties) {
super();
+ this.bootstrapProperties = bootstrapProperties;
}
- public static BootstrapContainer create(List objects) {
- BootstrapContainer container = new BootstrapContainer();
- container.add(objects);
+ public static BootstrapContainer create(Map<String, String> bootstrapProperties, List extensions) {
+ BootstrapContainer container = new BootstrapContainer(bootstrapProperties);
+ container.add(extensions);
return container;
}
@@ -84,7 +85,7 @@ public class BootstrapContainer extends ComponentContainer {
private void addBootstrapComponents() {
add(
new PropertiesConfiguration(),
- BootstrapSettings.class,
+ new BootstrapProperties(bootstrapProperties),
AnalysisMode.class,
PluginDownloader.class,
BatchPluginRepository.class,
@@ -100,21 +101,10 @@ public class BootstrapContainer extends ComponentContainer {
HttpDownloader.class,
UriReader.class,
new FileCacheProvider(),
- System2.INSTANCE,
- projectReactorBuilder());
- }
-
- private Class<?> projectReactorBuilder() {
- if (isRunnerVersionLessThan2Dot4()) {
- return DeprecatedProjectReactorBuilder.class;
+ System2.INSTANCE);
+ if (getComponentByType(SettingsReferential.class) == null) {
+ add(DefaultSettingsReferential.class);
}
- return ProjectReactorBuilder.class;
- }
-
- private boolean isRunnerVersionLessThan2Dot4() {
- EnvironmentInformation env = this.getComponentByType(EnvironmentInformation.class);
- // Starting from SQ Runner 2.4 the key is "SonarQubeRunner"
- return env != null && "SonarRunner".equals(env.getKey());
}
private void addDatabaseComponents() {
@@ -163,7 +153,6 @@ public class BootstrapContainer extends ComponentContainer {
@Override
protected void doAfterStart() {
installPlugins();
- executeTask();
}
private void installPlugins() {
@@ -174,7 +163,8 @@ public class BootstrapContainer extends ComponentContainer {
}
}
- void executeTask() {
- new TaskContainer(this).execute();
+ public void executeTask(Map<String, String> taskProperties) {
+ new TaskContainer(this, taskProperties).execute();
}
+
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapProperties.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapProperties.java
index 71b6e589a85..97db4c2b3df 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapProperties.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapProperties.java
@@ -19,24 +19,18 @@
*/
package org.sonar.batch.bootstrap;
-import com.google.common.collect.ImmutableMap;
+import org.sonar.api.CoreProperties;
import java.util.Map;
/**
- * Batch properties that are not specific to a project (for example
+ * Immutable batch properties that are not specific to a task (for example
* coming from global configuration file of sonar-runner).
*/
-public class BootstrapProperties {
-
- private final Map<String, String> properties;
+public class BootstrapProperties extends UserProperties {
public BootstrapProperties(Map<String, String> properties) {
- this.properties = ImmutableMap.copyOf(properties);
- }
-
- Map<String, String> properties() {
- return properties;
+ super(properties, properties.get(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java
deleted file mode 100644
index 179bc8db3ab..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.batch.bootstrap;
-
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.api.config.Encryption;
-
-import javax.annotation.Nullable;
-
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * @since 2.12
- */
-public class BootstrapSettings {
- private Map<String, String> properties;
- private final Encryption encryption;
-
- public BootstrapSettings(BootstrapProperties bootstrapProperties) {
- this(bootstrapProperties, null);
- }
-
- public BootstrapSettings(BootstrapProperties bootstrapProperties, @Nullable ProjectReactor projectReactor) {
- properties = Maps.newHashMap();
- // order is important -> bottom-up. The last one overrides all the others.
- properties.putAll(bootstrapProperties.properties());
- if (projectReactor != null) {
- addProperties(projectReactor.getRoot().getProperties());
- }
- properties.putAll(System.getenv());
- addProperties(System.getProperties());
- encryption = new Encryption(properties.get(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
- }
-
- private void addProperties(Properties p) {
- for (Map.Entry<Object, Object> entry : p.entrySet()) {
- if (entry.getValue() != null) {
- properties.put(entry.getKey().toString(), entry.getValue().toString());
- }
- }
- }
-
- public Map<String, String> properties() {
- return properties;
- }
-
- public String property(String key) {
- String value = properties.get(key);
- if (value != null && encryption.isEncrypted(value)) {
- try {
- value = encryption.decrypt(value);
- } catch (Exception e) {
- throw new IllegalStateException("Fail to decrypt the property " + key + ". Please check your secret key.", e);
- }
- }
- return value;
- }
-
- public String property(String key, String defaultValue) {
- return StringUtils.defaultString(property(key), defaultValue);
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java
index 111f28b36b8..d43ef8e0e71 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java
@@ -29,7 +29,6 @@ import org.apache.commons.lang.StringUtils;
import org.sonar.api.BatchComponent;
import org.sonar.api.CoreProperties;
import org.sonar.api.utils.HttpDownloader;
-import org.sonar.api.utils.SonarException;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import javax.annotation.Nullable;
@@ -47,16 +46,16 @@ import java.net.URI;
*/
public class ServerClient implements BatchComponent {
- private BootstrapSettings settings;
+ private BootstrapProperties props;
private HttpDownloader.BaseHttpDownloader downloader;
- public ServerClient(BootstrapSettings settings, EnvironmentInformation env) {
- this.settings = settings;
+ public ServerClient(BootstrapProperties settings, EnvironmentInformation env) {
+ this.props = settings;
this.downloader = new HttpDownloader.BaseHttpDownloader(settings.properties(), env.toString());
}
public String getURL() {
- return StringUtils.removeEnd(settings.property("sonar.host.url", "http://localhost:9000"), "/");
+ return StringUtils.removeEnd(StringUtils.defaultIfBlank(props.property("sonar.host.url"), "http://localhost:9000"), "/");
}
public void download(String pathStartingWithSlash, File toFile) {
@@ -70,7 +69,7 @@ public class ServerClient implements BatchComponent {
} catch (HttpDownloader.HttpException he) {
throw handleHttpException(he);
} catch (IOException e) {
- throw new SonarException(String.format("Unable to download '%s' to: %s", pathStartingWithSlash, toFile), e);
+ throw new IllegalStateException(String.format("Unable to download '%s' to: %s", pathStartingWithSlash, toFile), e);
}
}
@@ -89,7 +88,7 @@ public class ServerClient implements BatchComponent {
} catch (HttpDownloader.HttpException e) {
throw wrapHttpException ? handleHttpException(e) : e;
} catch (IOException e) {
- throw new SonarException(String.format("Unable to request: %s", pathStartingWithSlash), e);
+ throw new IllegalStateException(String.format("Unable to request: %s", pathStartingWithSlash), e);
}
}
@@ -107,19 +106,19 @@ public class ServerClient implements BatchComponent {
}
return inputSupplier;
} catch (Exception e) {
- throw new SonarException(String.format("Unable to request: %s", uri), e);
+ throw new IllegalStateException(String.format("Unable to request: %s", uri), e);
}
}
private RuntimeException handleHttpException(HttpDownloader.HttpException he) {
if (he.getResponseCode() == 401) {
- return new SonarException(String.format(getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD));
+ return new IllegalStateException(String.format(getMessageWhenNotAuthorized(), CoreProperties.LOGIN, CoreProperties.PASSWORD));
}
if (he.getResponseCode() == 403) {
// SONAR-4397 Details are in response content
- return new SonarException(he.getResponseContent());
+ return new IllegalStateException(he.getResponseContent());
}
- return new SonarException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he);
+ return new IllegalStateException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he);
}
private String getMessageWhenNotAuthorized() {
@@ -130,10 +129,10 @@ public class ServerClient implements BatchComponent {
}
private String getLogin() {
- return settings.property(CoreProperties.LOGIN);
+ return props.property(CoreProperties.LOGIN);
}
private String getPassword() {
- return settings.property(CoreProperties.PASSWORD);
+ return props.property(CoreProperties.PASSWORD);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
index b328680a990..4bdda269f46 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
@@ -26,17 +26,25 @@ import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.task.Task;
import org.sonar.api.task.TaskComponent;
import org.sonar.api.task.TaskDefinition;
-import org.sonar.api.utils.SonarException;
+import org.sonar.api.utils.MessageException;
+import org.sonar.batch.bootstrapper.EnvironmentInformation;
+import org.sonar.batch.scan.DeprecatedProjectReactorBuilder;
+import org.sonar.batch.scan.ProjectReactorBuilder;
import org.sonar.batch.scan.ScanTask;
import org.sonar.batch.tasks.ListTask;
import org.sonar.batch.tasks.Tasks;
import org.sonar.core.permission.PermissionFacade;
import org.sonar.core.resource.DefaultResourcePermissions;
+import java.util.Map;
+
public class TaskContainer extends ComponentContainer {
- public TaskContainer(ComponentContainer parent) {
+ private final Map<String, String> taskProperties;
+
+ public TaskContainer(ComponentContainer parent, Map<String, String> taskProperties) {
super(parent);
+ this.taskProperties = taskProperties;
}
@Override
@@ -46,10 +54,12 @@ public class TaskContainer extends ComponentContainer {
installComponentsUsingTaskExtensions();
}
- private void installCoreTasks() {
+ void installCoreTasks() {
+ add(new TaskProperties(taskProperties, getParent().getComponentByType(BootstrapProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)));
add(
ScanTask.DEFINITION, ScanTask.class,
- ListTask.DEFINITION, ListTask.class);
+ ListTask.DEFINITION, ListTask.class,
+ projectReactorBuilder());
}
private void installTaskExtensions() {
@@ -60,6 +70,19 @@ public class TaskContainer extends ComponentContainer {
});
}
+ private Class<?> projectReactorBuilder() {
+ if (isRunnerVersionLessThan2Dot4()) {
+ return DeprecatedProjectReactorBuilder.class;
+ }
+ return ProjectReactorBuilder.class;
+ }
+
+ private boolean isRunnerVersionLessThan2Dot4() {
+ EnvironmentInformation env = this.getComponentByType(EnvironmentInformation.class);
+ // Starting from SQ Runner 2.4 the key is "SonarQubeRunner"
+ return env != null && "SonarRunner".equals(env.getKey());
+ }
+
private void installComponentsUsingTaskExtensions() {
add(
ResourceTypes.class,
@@ -75,7 +98,7 @@ public class TaskContainer extends ComponentContainer {
TaskDefinition def = getComponentByType(Tasks.class).definition(taskKey);
if (def == null) {
- throw new SonarException("Task " + taskKey + " does not exist");
+ throw MessageException.of("Task " + taskKey + " does not exist");
}
Task task = getComponentByType(def.taskClass());
if (task != null) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskProperties.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskProperties.java
new file mode 100644
index 00000000000..d469fcdbe05
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskProperties.java
@@ -0,0 +1,36 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.bootstrap;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+/**
+ * Batch properties that are specific to a task (for example
+ * coming from sonar-project.properties).
+ */
+public class TaskProperties extends UserProperties {
+
+ public TaskProperties(Map<String, String> properties, @Nullable String pathToSecretKey) {
+ super(properties, pathToSecretKey);
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
index 267b29e3057..50a736b5e4c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
@@ -20,6 +20,7 @@
package org.sonar.batch.bootstrap;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties;
import org.sonar.api.utils.TempFolder;
@@ -30,8 +31,8 @@ import java.io.IOException;
public class TempFolderProvider extends ProviderAdapter {
- public TempFolder provide(BootstrapSettings bootstrapSettings) {
- String workingDirPath = bootstrapSettings.property(CoreProperties.WORKING_DIRECTORY, CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
+ public TempFolder provide(BootstrapProperties bootstrapProps) {
+ String workingDirPath = StringUtils.defaultIfBlank(bootstrapProps.property(CoreProperties.WORKING_DIRECTORY), CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
File workingDir = new File(workingDirPath);
File tempDir = new File(workingDir, ".sonartmp");
try {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/UserProperties.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/UserProperties.java
new file mode 100644
index 00000000000..42ae3d94a47
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/UserProperties.java
@@ -0,0 +1,62 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.bootstrap;
+
+import com.google.common.collect.Maps;
+import org.sonar.api.config.Encryption;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+/**
+ * Properties that are coming from bootstrapper.
+ */
+public abstract class UserProperties {
+
+ private final Map<String, String> properties;
+ private final Encryption encryption;
+
+ public UserProperties(Map<String, String> properties, @Nullable String pathToSecretKey) {
+ encryption = new Encryption(pathToSecretKey);
+ Map<String, String> decryptedProps = Maps.newHashMap();
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+ String value = entry.getValue();
+ if (value != null && encryption.isEncrypted(value)) {
+ try {
+ value = encryption.decrypt(value);
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to decrypt the property " + entry.getKey() + ". Please check your secret key.", e);
+ }
+ }
+ decryptedProps.put(entry.getKey(), value);
+ }
+ this.properties = Maps.newHashMap(decryptedProps);
+ }
+
+ public Map<String, String> properties() {
+ return properties;
+ }
+
+ public String property(String key) {
+ return properties.get(key);
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
index 9d90cf0b6ee..972450aebde 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
@@ -22,7 +22,6 @@ package org.sonar.batch.bootstrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.sonar.batch.bootstrap.BootstrapContainer;
-import org.sonar.batch.bootstrap.BootstrapProperties;
import java.util.Collections;
import java.util.List;
@@ -35,9 +34,11 @@ import java.util.Map;
*/
public final class Batch {
+ private boolean started = false;
private LoggingConfiguration logging;
private List<Object> components;
private Map<String, String> bootstrapProperties = Maps.newHashMap();
+ private BootstrapContainer bootstrapContainer;
private Batch(Builder builder) {
components = Lists.newArrayList();
@@ -57,24 +58,59 @@ public final class Batch {
return logging;
}
+ /**
+ * @deprecated since 4.4 use {@link #start()}, {@link #executeTask(Map)} and then {@link #stop()}
+ */
+ @Deprecated
public Batch execute() {
configureLogging();
- startBatch();
+ start().executeTask(bootstrapProperties).stop();
return this;
}
- private void configureLogging() {
- if (logging != null) {
- logging.configure();
+ /**
+ * @since 4.4
+ */
+ public synchronized Batch start() {
+ if (started) {
+ throw new IllegalStateException("Batch is already started");
}
+
+ configureLogging();
+ bootstrapContainer = BootstrapContainer.create(bootstrapProperties, components);
+ bootstrapContainer.startComponents();
+ this.started = true;
+
+ return this;
}
- private void startBatch() {
- List<Object> all = Lists.newArrayList(components);
- all.add(new BootstrapProperties(bootstrapProperties));
+ /**
+ * @since 4.4
+ */
+ public Batch executeTask(Map<String, String> taskProperties) {
+ if (!started) {
+ throw new IllegalStateException("Batch is not started. Unable to execute task.");
+ }
- BootstrapContainer bootstrapContainer = BootstrapContainer.create(all);
- bootstrapContainer.execute();
+ bootstrapContainer.executeTask(taskProperties);
+ return this;
+ }
+
+ /**
+ * @since 4.4
+ */
+ public synchronized void stop() {
+ if (!started) {
+ throw new IllegalStateException("Batch is not started.");
+ }
+
+ bootstrapContainer.stopComponents();
+ }
+
+ private void configureLogging() {
+ if (logging != null) {
+ logging.configure();
+ }
}
public static Builder builder() {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/DeprecatedProjectReactorBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/DeprecatedProjectReactorBuilder.java
index a0c3f5d173b..c9983e33243 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/DeprecatedProjectReactorBuilder.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/DeprecatedProjectReactorBuilder.java
@@ -20,7 +20,7 @@
package org.sonar.batch.scan;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.batch.bootstrap.BootstrapSettings;
+import org.sonar.batch.bootstrap.TaskProperties;
import java.io.File;
import java.io.IOException;
@@ -38,8 +38,8 @@ public class DeprecatedProjectReactorBuilder extends ProjectReactorBuilder {
private static final String PROPERTY_PROJECT_CONFIG_FILE = "sonar.projectConfigFile";
- public DeprecatedProjectReactorBuilder(BootstrapSettings settings) {
- super(settings);
+ public DeprecatedProjectReactorBuilder(TaskProperties props) {
+ super(props);
}
@Override
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java
index e10d8a6c984..da469b8bb89 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java
@@ -20,24 +20,20 @@
package org.sonar.batch.scan;
import com.google.common.collect.Lists;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
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.batch.bootstrap.ProjectDefinition;
import org.sonar.api.config.Settings;
-import org.sonar.api.utils.SonarException;
+import org.sonar.api.utils.MessageException;
import org.sonar.batch.bootstrap.AnalysisMode;
import org.sonar.batch.bootstrap.BatchSettings;
-import org.sonar.batch.bootstrap.ServerClient;
+import org.sonar.batch.settings.SettingsReferential;
import javax.annotation.Nullable;
-import java.util.List;
-import java.util.Map;
-import static org.sonar.batch.bootstrap.BatchSettings.BATCH_BOOTSTRAP_PROPERTIES_URL;
+import java.util.List;
/**
* @since 2.12
@@ -45,12 +41,13 @@ import static org.sonar.batch.bootstrap.BatchSettings.BATCH_BOOTSTRAP_PROPERTIES
public class ModuleSettings extends Settings {
private final Configuration deprecatedCommonsConf;
- private final ServerClient client;
+ private final SettingsReferential settingsReferential;
private AnalysisMode analysisMode;
- public ModuleSettings(BatchSettings batchSettings, ProjectDefinition project, Configuration deprecatedCommonsConf, ServerClient client, AnalysisMode analysisMode) {
+ public ModuleSettings(BatchSettings batchSettings, ProjectDefinition project, Configuration deprecatedCommonsConf, SettingsReferential settingsReferential,
+ AnalysisMode analysisMode) {
super(batchSettings.getDefinitions());
- this.client = client;
+ this.settingsReferential = settingsReferential;
this.analysisMode = analysisMode;
getEncryption().setPathToSecretKey(batchSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
@@ -62,8 +59,6 @@ public class ModuleSettings extends Settings {
private ModuleSettings init(ProjectDefinition project, BatchSettings batchSettings) {
addProjectProperties(project, batchSettings);
addBuildProperties(project);
- addEnvironmentVariables();
- addSystemProperties();
return this;
}
@@ -74,19 +69,7 @@ public class ModuleSettings extends Settings {
projectKey = String.format("%s:%s", projectKey, branch);
}
addProperties(batchSettings.getProperties());
- downloadSettings(projectKey);
- }
-
- private void downloadSettings(String moduleKey) {
- String url = BATCH_BOOTSTRAP_PROPERTIES_URL + "?project=" + moduleKey + "&dryRun=" + analysisMode.isPreview();
- String jsonText = client.request(url);
- List<Map<String, String>> json = new Gson().fromJson(jsonText, new TypeToken<List<Map<String, String>>>() {
- }.getType());
- for (Map<String, String> jsonProperty : json) {
- String key = jsonProperty.get("k");
- String value = jsonProperty.get("v");
- setProperty(key, value);
- }
+ addProperties(settingsReferential.projectSettings(projectKey));
}
private void addBuildProperties(ProjectDefinition project) {
@@ -127,7 +110,7 @@ public class ModuleSettings extends Settings {
@Override
protected void doOnGetProperties(String key) {
if (analysisMode.isPreview() && key.endsWith(".secured") && !key.contains(".license")) {
- throw new SonarException("Access to the secured property '" + key
+ throw MessageException.of("Access to the secured property '" + key
+ "' is not possible in preview mode. The SonarQube plugin which requires this property must be deactivated in preview mode.");
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorBuilder.java
index 6fcd09ad568..f1700a38fcb 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorBuilder.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectReactorBuilder.java
@@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.batch.bootstrap.BootstrapSettings;
+import org.sonar.batch.bootstrap.TaskProperties;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -101,16 +101,16 @@ public class ProjectReactorBuilder {
private static final List<String> NON_HERITED_PROPERTIES_FOR_CHILD = Lists.newArrayList(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES,
CoreProperties.PROJECT_DESCRIPTION_PROPERTY);
- private BootstrapSettings settings;
+ private TaskProperties props;
private File rootProjectWorkDir;
- public ProjectReactorBuilder(BootstrapSettings settings) {
- this.settings = settings;
+ public ProjectReactorBuilder(TaskProperties props) {
+ this.props = props;
}
public ProjectReactor execute() {
Properties bootstrapProperties = new Properties();
- bootstrapProperties.putAll(settings.properties());
+ bootstrapProperties.putAll(props.properties());
ProjectDefinition rootProject = defineProject(bootstrapProperties, null);
rootProjectWorkDir = rootProject.getWorkDir();
defineChildren(rootProject);
@@ -142,7 +142,7 @@ public class ProjectReactorBuilder {
@VisibleForTesting
protected File initRootProjectWorkDir(File baseDir) {
- String workDir = settings.property(CoreProperties.WORKING_DIRECTORY);
+ String workDir = props.property(CoreProperties.WORKING_DIRECTORY);
if (StringUtils.isBlank(workDir)) {
return new File(baseDir, CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index 335884d7f87..b6dca14dafd 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -35,7 +35,6 @@ import org.sonar.batch.DefaultFileLinesContextFactory;
import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectConfigurator;
import org.sonar.batch.ProjectTree;
-import org.sonar.batch.bootstrap.BootstrapSettings;
import org.sonar.batch.bootstrap.ExtensionInstaller;
import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
@@ -108,10 +107,10 @@ public class ProjectScanContainer extends ComponentContainer {
if (reactor == null) {
// OK, not present, so look for a custom ProjectBootstrapper
ProjectBootstrapper bootstrapper = getComponentByType(ProjectBootstrapper.class);
- BootstrapSettings settings = getComponentByType(BootstrapSettings.class);
+ Settings settings = getComponentByType(Settings.class);
if (bootstrapper == null
// Starting from Maven plugin 2.3 then only DefaultProjectBootstrapper should be used.
- || "true".equals(settings.property("sonar.mojoUseRunner"))) {
+ || "true".equals(settings.getString("sonar.mojoUseRunner"))) {
// Use default SonarRunner project bootstrapper
ProjectReactorBuilder builder = getComponentByType(ProjectReactorBuilder.class);
reactor = builder.execute();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/settings/DefaultSettingsReferential.java b/sonar-batch/src/main/java/org/sonar/batch/settings/DefaultSettingsReferential.java
new file mode 100644
index 00000000000..6241b0804dc
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/settings/DefaultSettingsReferential.java
@@ -0,0 +1,79 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.settings;
+
+import com.google.common.collect.Maps;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import org.sonar.batch.bootstrap.AnalysisMode;
+import org.sonar.batch.bootstrap.ServerClient;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Default implementation of {@link SettingsReferential} that fetch settings from remote SQ server using WS.
+ * @since 4.4
+ */
+public class DefaultSettingsReferential implements SettingsReferential {
+
+ private static final String BATCH_BOOTSTRAP_PROPERTIES_URL = "/batch_bootstrap/properties";
+
+ private final ServerClient serverClient;
+ private final AnalysisMode analysisMode;
+
+ public DefaultSettingsReferential(ServerClient serverClient, AnalysisMode analysisMode) {
+ this.serverClient = serverClient;
+ this.analysisMode = analysisMode;
+ }
+
+ @Override
+ public Map<String, String> globalSettings() {
+ return downloadSettings(null);
+ }
+
+ @Override
+ public Map<String, String> projectSettings(String moduleKey) {
+ return downloadSettings(moduleKey);
+ }
+
+ private Map<String, String> downloadSettings(@Nullable String moduleKey) {
+ Map<String, String> result = Maps.newHashMap();
+ String url = BATCH_BOOTSTRAP_PROPERTIES_URL + "?dryRun=" + analysisMode.isPreview();
+ if (moduleKey != null) {
+ url += "&project=" + moduleKey;
+ }
+ String jsonText = serverClient.request(url);
+
+ List<Map<String, String>> json = new Gson().fromJson(jsonText, new TypeToken<List<Map<String, String>>>() {
+ }.getType());
+
+ for (Map<String, String> jsonProperty : json) {
+ String key = jsonProperty.get("k");
+ String value = jsonProperty.get("v");
+ result.put(key, value);
+ }
+
+ return result;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/settings/SettingsReferential.java b/sonar-batch/src/main/java/org/sonar/batch/settings/SettingsReferential.java
new file mode 100644
index 00000000000..d4d7367e3ea
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/settings/SettingsReferential.java
@@ -0,0 +1,43 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.settings;
+
+import org.sonar.api.BatchComponent;
+
+import java.util.Map;
+
+/**
+ * Settings referential
+ * @since 4.4
+ */
+public interface SettingsReferential extends BatchComponent {
+
+ /**
+ * Provide global settings
+ */
+ Map<String, String> globalSettings();
+
+ /**
+ * Provide settings for a given project or sub-project (includes global settings)
+ * @param projectKey
+ */
+ Map<String, String> projectSettings(String projectKey);
+
+}