diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2014-06-09 15:16:10 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2014-06-10 12:36:10 +0200 |
commit | da92c49827337bd34fbf077d5d74c9fbfb8ec287 (patch) | |
tree | 8e53db0de00d84dc712ad69904105430e65f8e6f /sonar-batch/src/main | |
parent | 5d0730e2be1a25c186049a3255c50772818ae4c1 (diff) | |
download | sonarqube-da92c49827337bd34fbf077d5d74c9fbfb8ec287.tar.gz sonarqube-da92c49827337bd34fbf077d5d74c9fbfb8ec287.zip |
Separate bootstrap settings and task settings
Diffstat (limited to 'sonar-batch/src/main')
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); + +} |