From 2bdd7679edce5c08f5d9ee8f232bd2f96d7973e7 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 5 Nov 2012 22:54:34 +0100 Subject: [PATCH] SONAR-3895 optimize loading of project settings --- sonar-batch/pom.xml | 4 - .../sonar/batch/bootstrap/BatchModule.java | 1 + .../bootstrap/BatchPluginRepository.java | 1 - .../sonar/batch/bootstrap/BatchSettings.java | 105 ++++++++++++++++ .../batch/bootstrap/BootstrapModule.java | 6 - .../BootstrapSettings.java | 26 ++-- .../sonar/batch/bootstrap/ProjectModule.java | 2 - .../ProjectSettings.java | 38 +++--- .../UnsupportedProperties.java | 2 +- .../sonar/batch/bootstrap/WsConnector.java | 75 ----------- .../batch/config/BootstrapSettingsLoader.java | 69 ----------- .../org/sonar/batch/local/DryRunDatabase.java | 19 ++- .../batch/bootstrap/BatchSettingsTest.java | 116 ++++++++++++++++++ .../BootstrapSettingsTest.java | 24 ++-- .../batch/bootstrap/ProjectModuleTest.java | 9 +- .../ProjectSettingsTest.java | 3 +- .../UnsupportedPropertiesTest.java | 3 +- .../sonar/batch/local/DryRunDatabaseTest.java | 8 +- .../app/controllers/api/synchro_controller.rb | 48 -------- .../controllers/batch_bootstrap_controller.rb | 69 +++++++++++ 20 files changed, 361 insertions(+), 267 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java rename sonar-batch/src/main/java/org/sonar/batch/{config => bootstrap}/BootstrapSettings.java (78%) rename sonar-batch/src/main/java/org/sonar/batch/{config => bootstrap}/ProjectSettings.java (69%) rename sonar-batch/src/main/java/org/sonar/batch/{config => bootstrap}/UnsupportedProperties.java (97%) delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsConnector.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java rename sonar-batch/src/test/java/org/sonar/batch/{config => bootstrap}/BootstrapSettingsTest.java (73%) rename sonar-batch/src/test/java/org/sonar/batch/{config => bootstrap}/ProjectSettingsTest.java (94%) rename sonar-batch/src/test/java/org/sonar/batch/{config => bootstrap}/UnsupportedPropertiesTest.java (94%) delete mode 100644 sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml index e693da1521a..5a05eb10354 100644 --- a/sonar-batch/pom.xml +++ b/sonar-batch/pom.xml @@ -34,10 +34,6 @@ org.codehaus.sonar sonar-squid - - org.codehaus.sonar - sonar-ws-client - org.slf4j slf4j-api diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java index 0414d6ee424..85901d68b74 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java @@ -70,6 +70,7 @@ public class BatchModule extends Module { } private void registerCoreComponents() { + container.addSingleton(BatchSettings.class); container.addSingleton(EmailSettings.class); container.addSingleton(I18nManager.class); container.addSingleton(RuleI18nManager.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java index d0674039a48..2adca6754bb 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java @@ -30,7 +30,6 @@ import org.sonar.api.Plugin; import org.sonar.api.config.Settings; import org.sonar.api.platform.PluginMetadata; import org.sonar.api.platform.PluginRepository; -import org.sonar.batch.config.BootstrapSettings; import org.sonar.core.plugins.PluginClassloaders; import org.sonar.core.plugins.PluginInstaller; import org.sonar.core.plugins.RemotePlugin; 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 new file mode 100644 index 00000000000..f620b6d0e7b --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java @@ -0,0 +1,105 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrap; + +import com.google.common.collect.Maps; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang.StringUtils; +import org.json.simple.JSONValue; +import org.slf4j.LoggerFactory; +import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.config.Settings; + +import javax.annotation.Nullable; + +import java.util.List; +import java.util.Map; + +public class BatchSettings extends Settings { + private Configuration deprecatedConfiguration; + + // Keep module settings for initialization of ProjectSettings + // module key -> + private Map> moduleProperties = Maps.newHashMap(); + + public BatchSettings(BootstrapSettings bootstrapSettings, ProjectReactor reactor, ServerClient client, + Configuration deprecatedConfiguration) { + super(bootstrapSettings.getDefinitions()); + this.deprecatedConfiguration = deprecatedConfiguration; + init(bootstrapSettings, reactor, client); + } + + private void init(BootstrapSettings bootstrapSettings, ProjectReactor reactor, ServerClient client) { + LoggerFactory.getLogger(BatchSettings.class).info("Load project settings"); + + String branch = bootstrapSettings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); + String projectKey = reactor.getRoot().getKey(); + if (StringUtils.isNotBlank(branch)) { + projectKey = String.format("%s:%s", projectKey, branch); + } + downloadSettings(client, projectKey); + + + // order is important -> bottom-up. The last one overrides all the others. + addProperties(reactor.getRoot().getProperties()); + addEnvironmentVariables(); + addSystemProperties(); + } + + private void downloadSettings(ServerClient client, String projectKey) { + String jsonText = client.request("/batch_bootstrap/properties?project=" + projectKey); + List> json = (List>) JSONValue.parse(jsonText); + for (Map jsonProperty : json) { + String key = jsonProperty.get("k"); + String value = jsonProperty.get("v"); + String moduleKey = jsonProperty.get("p"); + if (moduleKey == null || projectKey.equals(moduleKey)) { + setProperty(key, value); + } else { + Map map = moduleProperties.get(moduleKey); + if (map == null) { + map = Maps.newHashMap(); + moduleProperties.put(moduleKey, map); + } + map.put(key, value); + } + } + } + + public Map getModuleProperties(String projectKey) { + return moduleProperties.get(projectKey); + } + + @Override + protected void doOnSetProperty(String key, @Nullable String value) { + deprecatedConfiguration.setProperty(key, value); + } + + @Override + protected void doOnRemoveProperty(String key) { + deprecatedConfiguration.clearProperty(key); + } + + @Override + protected void doOnClearProperties() { + deprecatedConfiguration.clear(); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java index 6951993e578..31d7fcb5846 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java @@ -26,10 +26,7 @@ import org.sonar.api.utils.UriReader; import org.sonar.batch.FakeMavenPluginExecutor; import org.sonar.batch.MavenPluginExecutor; import org.sonar.batch.ServerMetadata; -import org.sonar.batch.config.BootstrapSettings; -import org.sonar.batch.config.BootstrapSettingsLoader; import org.sonar.core.config.Logback; -import org.sonar.wsclient.Sonar; /** * Level 1 components @@ -55,13 +52,10 @@ public class BootstrapModule extends Module { container.addSingleton(Logback.class); container.addSingleton(ServerClient.class); container.addSingleton(ServerMetadata.class); - container.addSingleton(WsConnector.class); - container.addSingleton(Sonar.class); container.addSingleton(TempDirectories.class); container.addSingleton(HttpDownloader.class); container.addSingleton(UriReader.class); container.addSingleton(PluginDownloader.class); - container.addSingleton(BootstrapSettingsLoader.class); for (Object component : boostrapperComponents) { if (component != null) { container.addSingleton(component); diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java similarity index 78% rename from sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java rename to sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java index 1d7caab9509..ccd87b92176 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java @@ -17,13 +17,14 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.config; +package org.sonar.batch.bootstrap; import org.apache.commons.configuration.Configuration; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.Settings; -import org.sonar.core.config.ConfigurationUtils; + +import javax.annotation.Nullable; /** * @since 2.12 @@ -36,23 +37,28 @@ public class BootstrapSettings extends Settings { super(propertyDefinitions); this.reactor = reactor; this.deprecatedConfiguration = deprecatedConfiguration; - load(); + init(); } - private BootstrapSettings load() { - clear(); - + private void init() { // order is important -> bottom-up. The last one overrides all the others. addProperties(reactor.getRoot().getProperties()); addEnvironmentVariables(); addSystemProperties(); + } - updateDeprecatedCommonsConfiguration(); + @Override + protected void doOnSetProperty(String key, @Nullable String value) { + deprecatedConfiguration.setProperty(key, value); + } - return this; + @Override + protected void doOnRemoveProperty(String key) { + deprecatedConfiguration.clearProperty(key); } - public void updateDeprecatedCommonsConfiguration() { - ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedConfiguration); + @Override + protected void doOnClearProperties() { + deprecatedConfiguration.clear(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java index 0acaa7c9ba0..8e7a22c33ef 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java @@ -37,8 +37,6 @@ import org.sonar.batch.ProjectTree; import org.sonar.batch.ResourceFilters; import org.sonar.batch.ViolationFilters; import org.sonar.batch.components.TimeMachineConfiguration; -import org.sonar.batch.config.ProjectSettings; -import org.sonar.batch.config.UnsupportedProperties; import org.sonar.batch.events.EventBus; import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.ResourcePersister; diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectSettings.java similarity index 69% rename from sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java rename to sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectSettings.java index 330100f328b..9a35a3ef117 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectSettings.java @@ -17,7 +17,7 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.config; +package org.sonar.batch.bootstrap; import com.google.common.collect.Lists; import org.apache.commons.configuration.Configuration; @@ -26,14 +26,11 @@ 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.core.config.ConfigurationUtils; -import org.sonar.wsclient.Sonar; -import org.sonar.wsclient.services.Property; -import org.sonar.wsclient.services.PropertyQuery; import javax.annotation.Nullable; import java.util.List; +import java.util.Map; /** * @since 2.12 @@ -42,41 +39,44 @@ public class ProjectSettings extends Settings { private Configuration deprecatedCommonsConf; - public ProjectSettings(BootstrapSettings bootstrapSettings, ProjectDefinition project, - Sonar wsClient, Configuration deprecatedCommonsConf) { - super(bootstrapSettings.getDefinitions()); + public ProjectSettings(BatchSettings batchSettings, ProjectDefinition project, Configuration deprecatedCommonsConf) { + super(batchSettings.getDefinitions()); LoggerFactory.getLogger(ProjectSettings.class).info("Load module settings"); this.deprecatedCommonsConf = deprecatedCommonsConf; if (project.getParent() == null) { // root project -> no need to reload settings - copy(bootstrapSettings); + copy(batchSettings); } else { - init(project, bootstrapSettings, wsClient); + init(project, batchSettings); } } - private void copy(BootstrapSettings bootstrapSettings) { - setProperties(bootstrapSettings); + private void copy(BatchSettings batchSettings) { + setProperties(batchSettings); } - private ProjectSettings init(ProjectDefinition project, BootstrapSettings bootstrapSettings, Sonar wsClient) { - addPersistedProperties(project, bootstrapSettings, wsClient); + private ProjectSettings init(ProjectDefinition project, BatchSettings batchSettings) { + addProjectProperties(project, batchSettings); addBuildProperties(project); addEnvironmentVariables(); addSystemProperties(); + //addProgrammaticProperties(); return this; } - private void addPersistedProperties(ProjectDefinition project, BootstrapSettings bootstrapSettings, Sonar wsClient) { - String branch = bootstrapSettings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); + private void addProjectProperties(ProjectDefinition project, BatchSettings batchSettings) { + String branch = batchSettings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); String projectKey = project.getKey(); if (StringUtils.isNotBlank(branch)) { projectKey = String.format("%s:%s", projectKey, branch); } - List wsProperties = wsClient.findAll(PropertyQuery.createForAll().setResourceKeyOrId(projectKey)); - for (Property wsProperty : wsProperties) { - setProperty(wsProperty.getKey(), wsProperty.getValue()); + addProperties(batchSettings.getProperties()); + Map moduleProps = batchSettings.getModuleProperties(projectKey); + if (moduleProps != null) { + for (Map.Entry entry : moduleProps.entrySet()) { + setProperty(entry.getKey(), entry.getValue()); + } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/UnsupportedProperties.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/UnsupportedProperties.java similarity index 97% rename from sonar-batch/src/main/java/org/sonar/batch/config/UnsupportedProperties.java rename to sonar-batch/src/main/java/org/sonar/batch/bootstrap/UnsupportedProperties.java index 554bac7240e..6d6661255eb 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/config/UnsupportedProperties.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/UnsupportedProperties.java @@ -17,7 +17,7 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.config; +package org.sonar.batch.bootstrap; import org.sonar.api.BatchComponent; import org.sonar.api.config.Settings; diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsConnector.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsConnector.java deleted file mode 100644 index 9e7dc579532..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsConnector.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.bootstrap; - -import org.sonar.wsclient.connectors.Connector; -import org.sonar.wsclient.services.CreateQuery; -import org.sonar.wsclient.services.DeleteQuery; -import org.sonar.wsclient.services.Query; -import org.sonar.wsclient.services.UpdateQuery; - -/** - * @since 3.4 - */ -public class WsConnector extends Connector { - - private ServerClient server; - - public WsConnector(ServerClient server) { - this.server = server; - } - - /** - * @return JSON response or null if 404 NOT FOUND error - * @throws org.sonar.wsclient.connectors.ConnectionException - * if connection error or HTTP status not in (200, 404) - */ - @Override - public String execute(Query query) { - return server.request(query.getUrl()); - } - - /** - * @return JSON response or null if 404 NOT FOUND error - * @since 2.2 - */ - @Override - public String execute(CreateQuery query) { - throw new UnsupportedOperationException(); - } - - /** - * @return JSON response or null if 404 NOT FOUND error - * @since 2.2 - */ - @Override - public String execute(DeleteQuery query) { - throw new UnsupportedOperationException(); - } - - /** - * @return JSON response or null if 404 NOT FOUND error - * @since 2.6 - */ - @Override - public String execute(UpdateQuery query) { - throw new UnsupportedOperationException(); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java deleted file mode 100644 index 02563c7a240..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/config/BootstrapSettingsLoader.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.config; - -import org.apache.commons.lang.StringUtils; -import org.slf4j.LoggerFactory; -import org.sonar.api.CoreProperties; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.wsclient.Sonar; -import org.sonar.wsclient.services.Property; -import org.sonar.wsclient.services.PropertyQuery; - -import java.util.List; - -/** - * Load global settings and project settings. Note that the definition of modules is - * incomplete before the execution of ProjectBuilder extensions, so module settings - * are not loaded yet. - * @since 3.4 - */ -public final class BootstrapSettingsLoader { - - private BootstrapSettings settings; - private ProjectReactor reactor; - private Sonar wsClient; - - public BootstrapSettingsLoader(BootstrapSettings settings, ProjectReactor reactor, Sonar wsClient) { - this.settings = settings; - this.reactor = reactor; - this.wsClient = wsClient; - } - - public void start() { - LoggerFactory.getLogger(BootstrapSettingsLoader.class).info("Load project settings"); - String branch = settings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY); - String projectKey = reactor.getRoot().getKey(); - if (StringUtils.isNotBlank(branch)) { - projectKey = String.format("%s:%s", projectKey, branch); - } - List wsProperties = wsClient.findAll(PropertyQuery.createForAll().setResourceKeyOrId(projectKey)); - for (Property wsProperty : wsProperties) { - setIfNotDefined(wsProperty); - } - settings.updateDeprecatedCommonsConfiguration(); - } - - private void setIfNotDefined(Property wsProperty) { - if (!settings.hasKey(wsProperty.getKey())) { - settings.setProperty(wsProperty.getKey(), wsProperty.getValue()); - } - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java index 4149940feb8..9e5115671a3 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java +++ b/sonar-batch/src/main/java/org/sonar/batch/local/DryRunDatabase.java @@ -43,7 +43,6 @@ import java.io.IOException; public class DryRunDatabase implements BatchComponent { private static final Logger LOG = LoggerFactory.getLogger(DryRunDatabase.class); - private static final String API_SYNCHRO = "/api/synchro"; private static final String DIALECT = "h2"; private static final String DRIVER = "org.h2.Driver"; private static final String URL = "jdbc:h2:"; @@ -57,8 +56,8 @@ public class DryRunDatabase implements BatchComponent { private final ProjectReactor reactor; public DryRunDatabase(DryRun dryRun, Settings settings, ServerClient server, TempDirectories tempDirectories, ProjectReactor reactor, - // project reactor must be completely built - ProjectReactorReady reactorReady) { + // project reactor must be completely built + ProjectReactorReady reactorReady) { this.dryRun = dryRun; this.settings = settings; this.server = server; @@ -81,7 +80,7 @@ public class DryRunDatabase implements BatchComponent { private void downloadDatabase(String projectKey, File toFile) { try { - server.download(API_SYNCHRO + "?resource=" + projectKey, toFile); + server.download("/batch_bootstrap/db?project=" + projectKey, toFile); } catch (SonarException e) { Throwable rootCause = Throwables.getRootCause(e); if (rootCause instanceof FileNotFoundException) { @@ -95,11 +94,11 @@ public class DryRunDatabase implements BatchComponent { private void replaceSettings(String databasePath) { settings - .setProperty("sonar.jdbc.schema", "") - .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) - .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER) - .setProperty(DatabaseProperties.PROP_USER, USER) - .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD) - .setProperty(DatabaseProperties.PROP_URL, URL + databasePath); + .setProperty("sonar.jdbc.schema", "") + .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) + .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER) + .setProperty(DatabaseProperties.PROP_USER, USER) + .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD) + .setProperty(DatabaseProperties.PROP_URL, URL + databasePath); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java new file mode 100644 index 00000000000..501a7dfbc8e --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java @@ -0,0 +1,116 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrap; + +import org.apache.commons.configuration.BaseConfiguration; +import org.apache.commons.configuration.Configuration; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.config.PropertyDefinitions; + +import java.util.Map; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class BatchSettingsTest { + + Configuration deprecatedConf; + ServerClient client; + ProjectDefinition project; + ProjectReactor reactor; + BootstrapSettings bootstrapSettings; + + @Before + public void before() { + project = ProjectDefinition.create(); + project.setKey("struts"); + reactor = new ProjectReactor(project); + deprecatedConf = new BaseConfiguration(); + client = mock(ServerClient.class); + when(client.request("/batch_bootstrap/properties?project=struts")).thenReturn( + "[{\"k\":\"sonar.cpd.cross\",\"v\":\"true\"}," + + "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"jacoco\",\"p\":\"struts\"}," + + "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"cobertura\",\"p\":\"struts-core\"}]" + ); + bootstrapSettings = new BootstrapSettings(new PropertyDefinitions(), reactor, deprecatedConf); + } + + @Test + public void should_load_system_props() { + System.setProperty("BatchSettingsTest.testSystemProp", "system"); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + assertThat(batchSettings.getString("BatchSettingsTest.testSystemProp")).isEqualTo("system"); + } + + @Test + public void should_load_build_props() { + project.setProperty("build.prop", "build"); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + assertThat(batchSettings.getString("build.prop")).isEqualTo("build"); + } + + @Test + public void should_load_global_settings() { + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + assertThat(batchSettings.getBoolean("sonar.cpd.cross")).isTrue(); + } + + @Test + public void should_load_project_root_settings() { + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + assertThat(batchSettings.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); + } + + @Test + public void should_keep_module_settings_for_later() { + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + Map moduleSettings = batchSettings.getModuleProperties("struts-core"); + assertThat(moduleSettings).hasSize(1); + assertThat(moduleSettings.get("sonar.java.coveragePlugin")).isEqualTo("cobertura"); + } + + @Test + public void system_props_should_override_build_props() { + System.setProperty("BatchSettingsTest.testSystemProp", "system"); + project.setProperty("BatchSettingsTest.testSystemProp", "build"); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + assertThat(batchSettings.getString("BatchSettingsTest.testSystemProp")).isEqualTo("system"); + } + + @Test + public void should_forward_to_deprecated_commons_configuration() { + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, reactor, client, deprecatedConf); + + assertThat(deprecatedConf.getString("sonar.cpd.cross")).isEqualTo("true"); + assertThat(deprecatedConf.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); + + batchSettings.removeProperty("sonar.cpd.cross"); + assertThat(deprecatedConf.getString("sonar.cpd.cross")).isNull(); + assertThat(deprecatedConf.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); + + batchSettings.clear(); + assertThat(deprecatedConf.getString("sonar.cpd.cross")).isNull(); + assertThat(deprecatedConf.getString("sonar.java.coveragePlugin")).isNull(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/config/BootstrapSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java similarity index 73% rename from sonar-batch/src/test/java/org/sonar/batch/config/BootstrapSettingsTest.java rename to sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java index 1d68dfa3cdc..df01592816b 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/config/BootstrapSettingsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java @@ -17,7 +17,7 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.config; +package org.sonar.batch.bootstrap; import org.apache.commons.configuration.BaseConfiguration; import org.junit.Test; @@ -25,8 +25,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.PropertyDefinitions; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; public class BootstrapSettingsTest { @@ -39,7 +38,7 @@ public class BootstrapSettingsTest { ProjectReactor reactor = new ProjectReactor(project); BootstrapSettings settings = new BootstrapSettings(new PropertyDefinitions(), reactor, new BaseConfiguration()); - assertThat(settings.getString("foo"), is("bar")); + assertThat(settings.getString("foo")).isEqualTo("bar"); } @Test @@ -51,18 +50,27 @@ public class BootstrapSettingsTest { ProjectReactor reactor = new ProjectReactor(project); BootstrapSettings settings = new BootstrapSettings(new PropertyDefinitions(), reactor, new BaseConfiguration()); - assertThat(settings.getString("BootstrapSettingsTest.testEnv"), is("env")); + assertThat(settings.getString("BootstrapSettingsTest.testEnv")).isEqualTo("env"); } @Test public void shouldForwardToCommonsConfiguration() { ProjectDefinition project = ProjectDefinition.create(); + project.setProperty("hello", "world"); project.setProperty("foo", "bar"); - ProjectReactor reactor = new ProjectReactor(project); BaseConfiguration deprecatedConfiguration = new BaseConfiguration(); - new BootstrapSettings(new PropertyDefinitions(), reactor, deprecatedConfiguration); + BootstrapSettings settings = new BootstrapSettings(new PropertyDefinitions(), reactor, deprecatedConfiguration); + + assertThat(deprecatedConfiguration.getString("hello")).isEqualTo("world"); + assertThat(deprecatedConfiguration.getString("foo")).isEqualTo("bar"); + + settings.removeProperty("foo"); + assertThat(deprecatedConfiguration.getString("foo")).isNull(); + assertThat(deprecatedConfiguration.getString("hello")).isEqualTo("world"); - assertThat(deprecatedConfiguration.getString("foo"), is("bar")); + settings.clear(); + assertThat(deprecatedConfiguration.getString("foo")).isNull(); + assertThat(deprecatedConfiguration.getString("hello")).isNull(); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java index adad9113158..df8e0f6a949 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java @@ -22,8 +22,6 @@ package org.sonar.batch.bootstrap; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Test; import org.mockito.Matchers; -import org.mockito.MockSettings; -import org.mockito.Mockito; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.database.model.Snapshot; @@ -31,11 +29,7 @@ import org.sonar.api.platform.ComponentContainer; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.batch.ProjectTree; -import org.sonar.batch.config.BootstrapSettings; -import org.sonar.batch.config.ProjectSettings; import org.sonar.batch.index.ResourcePersister; -import org.sonar.core.properties.PropertiesDao; -import org.sonar.wsclient.Sonar; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; @@ -62,8 +56,7 @@ public class ProjectModuleTest { container.addSingleton(extensionInstaller); container.addSingleton(projectTree); container.addSingleton(resourcePersister); - container.addSingleton(mock(Sonar.class)); - container.addSingleton(mock(BootstrapSettings.class)); + container.addSingleton(mock(BatchSettings.class)); } }; diff --git a/sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectSettingsTest.java similarity index 94% rename from sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java rename to sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectSettingsTest.java index 753a09921a8..5798595a885 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/config/ProjectSettingsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectSettingsTest.java @@ -17,11 +17,12 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.config; +package org.sonar.batch.bootstrap; import org.hamcrest.core.Is; import org.junit.Test; import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.batch.bootstrap.ProjectSettings; import java.util.List; diff --git a/sonar-batch/src/test/java/org/sonar/batch/config/UnsupportedPropertiesTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/UnsupportedPropertiesTest.java similarity index 94% rename from sonar-batch/src/test/java/org/sonar/batch/config/UnsupportedPropertiesTest.java rename to sonar-batch/src/test/java/org/sonar/batch/bootstrap/UnsupportedPropertiesTest.java index 6c042280b48..0b8d35d43f0 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/config/UnsupportedPropertiesTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/UnsupportedPropertiesTest.java @@ -17,12 +17,13 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch.config; +package org.sonar.batch.bootstrap; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.Settings; +import org.sonar.batch.bootstrap.UnsupportedProperties; public class UnsupportedPropertiesTest { diff --git a/sonar-batch/src/test/java/org/sonar/batch/local/DryRunDatabaseTest.java b/sonar-batch/src/test/java/org/sonar/batch/local/DryRunDatabaseTest.java index e2b3d27b816..e3cb4ce7fad 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/local/DryRunDatabaseTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/local/DryRunDatabaseTest.java @@ -76,7 +76,7 @@ public class DryRunDatabaseTest { dryRunDatabase.start(); - verify(server).download("/api/synchro?resource=group:project", databaseFile); + verify(server).download("/batch_bootstrap/db?project=group:project", databaseFile); } @Test @@ -97,7 +97,7 @@ public class DryRunDatabaseTest { public void should_fail_on_unknown_project() { when(dryRun.isEnabled()).thenReturn(true); when(tempDirectories.getFile("dry_run", "db.h2.db")).thenReturn(new File("/tmp/dry_run/db.h2.db")); - doThrow(new SonarException(new FileNotFoundException())).when(server).download("/api/synchro?resource=group:project", new File("/tmp/dry_run/db.h2.db")); + doThrow(new SonarException(new FileNotFoundException())).when(server).download("/batch_bootstrap/db?project=group:project", new File("/tmp/dry_run/db.h2.db")); thrown.expect(SonarException.class); thrown.expectMessage("Project [group:project] doesn't exist on server"); @@ -109,7 +109,7 @@ public class DryRunDatabaseTest { public void should_fail_on_invalid_role() { when(dryRun.isEnabled()).thenReturn(true); when(tempDirectories.getFile("dry_run", "db.h2.db")).thenReturn(new File("/tmp/dry_run/db.h2.db")); - doThrow(new SonarException(new IOException("HTTP 401"))).when(server).download("/api/synchro?resource=group:project", new File("/tmp/dry_run/db.h2.db")); + doThrow(new SonarException(new IOException("HTTP 401"))).when(server).download("/batch_bootstrap/db?project=group:project", new File("/tmp/dry_run/db.h2.db")); thrown.expect(SonarException.class); thrown.expectMessage("You don't have access rights to project [group:project]"); @@ -121,7 +121,7 @@ public class DryRunDatabaseTest { public void should_fail() { when(dryRun.isEnabled()).thenReturn(true); when(tempDirectories.getFile("dry_run", "db.h2.db")).thenReturn(new File("/tmp/dry_run/db.h2.db")); - doThrow(new SonarException("BUG")).when(server).download("/api/synchro?resource=group:project", new File("/tmp/dry_run/db.h2.db")); + doThrow(new SonarException("BUG")).when(server).download("/batch_bootstrap/db?project=group:project", new File("/tmp/dry_run/db.h2.db")); thrown.expect(SonarException.class); thrown.expectMessage("BUG"); diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb deleted file mode 100644 index e85190acfbd..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Sonar, entreprise quality control tool. -# Copyright (C) 2008-2012 SonarSource -# mailto:contact AT sonarsource DOT com -# -# Sonar is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 3 of the License, or (at your option) any later version. -# -# Sonar is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with Sonar; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 -# - -require "json" - -class Api::SynchroController < Api::ApiController - - # curl http://localhost:9000/api/synchro?resource= -v [-u user:password] - def index - require_parameters :resource - load_resource() - - resource_id = @resource.id if @resource - dbFileContent = java_facade.createDatabaseForDryRun(resource_id) - - send_data String.from_java_bytes(dbFileContent) - end - - private - - def load_resource - resource_key = params[:resource] - @resource = Project.by_key(resource_key) - if @resource - access_denied unless is_user?(@resource) - else - #access_denied unless is_user?(nil) - end - end -end - diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb new file mode 100644 index 00000000000..9ba5f005c2c --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb @@ -0,0 +1,69 @@ +# +# Sonar, entreprise quality control tool. +# Copyright (C) 2008-2012 SonarSource +# mailto:contact AT sonarsource DOT com +# +# Sonar is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# Sonar is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with Sonar; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 +# + +# Since 3.4 +class BatchBootstrapController < ApplicationController + + # GET /batch_bootstrap/db?project= + def db + require_parameters :project + project = load_project() + db_content = java_facade.createDatabaseForDryRun(project ? project.id : nil) + + send_data String.from_java_bytes(db_content) + end + + # GET /batch_bootstrap/properties?project= + def properties + require_parameters :project + + json_properties=Property.find(:all, :conditions => ['user_id is null and resource_id is null']).map{|property| to_json_property(property)} + + root_project = load_project() + if root_project + Project.find(:all, :select => 'id,kee', :conditions => ['enabled=? and (root_id=? or id=?)', true, root_project.id, root_project.id]).each do |project| + json_properties.concat(Property.find(:all, :conditions => ['user_id is null and resource_id=?', project.id]).map{|property| to_json_property(property, project.kee)}) + end + end + + has_admin_role=has_role?(:admin, root_project) + json_properties=json_properties.select{|prop| allowed?(prop[:k], has_admin_role)} + + render :json => JSON(json_properties) + end + + private + + def load_project + project = Project.by_key(params[:project]) + return access_denied if project && !has_role?(:user, project) + project + end + + def to_json_property(property, project_key=nil) + hash={:k => property.key, :v => property.text_value.to_s} + hash[:p]=project_key if project_key + hash + end + + def allowed?(property_key, has_admin_role) + !property_key.end_with?('.secured') || has_admin_role + end +end \ No newline at end of file -- 2.39.5