From: Simon Brandhof Date: Mon, 5 Feb 2018 13:48:50 +0000 (+0100) Subject: Add Java API Plugin.Context#getBootConfiguration() X-Git-Tag: 7.5~1741 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3c42d5d2e6b362d389c0058e069897bf26ef65f7;p=sonarqube.git Add Java API Plugin.Context#getBootConfiguration() That allows plugins to check configuration when providing the list of extensions. --- diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java index e9703dc34de..fa1cb855b2b 100644 --- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java +++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import org.sonar.api.Plugin; import org.sonar.api.SonarQubeSide; import org.sonar.api.SonarRuntime; +import org.sonar.api.internal.PluginContextImpl; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.utils.Version; import org.sonar.xoo.lang.CpdTokenizerSensor; @@ -34,7 +35,7 @@ public class XooPluginTest { @Test public void provide_extensions_for_5_4() { SonarRuntime runtime = SonarRuntimeImpl.forSonarLint(Version.parse("5.4")); - Plugin.Context context = new Plugin.Context(runtime); + Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build(); new XooPlugin().define(context); assertThat(context.getExtensions()).hasSize(46).doesNotContain(CpdTokenizerSensor.class); } @@ -42,7 +43,7 @@ public class XooPluginTest { @Test public void provide_extensions_for_5_5() { SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("5.5"), SonarQubeSide.SCANNER); - Plugin.Context context = new Plugin.Context(runtime); + Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build(); new XooPlugin().define(context); assertThat(context.getExtensions()).hasSize(49).contains(CpdTokenizerSensor.class); } @@ -50,7 +51,7 @@ public class XooPluginTest { @Test public void provide_extensions_for_6_6() { SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("6.6"), SonarQubeSide.SCANNER); - Plugin.Context context = new Plugin.Context(runtime); + Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build(); new XooPlugin().define(context); assertThat(context.getExtensions()).hasSize(50).contains(CpdTokenizerSensor.class); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java index f584c2eb3b8..f6fe4d1dadd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java @@ -30,6 +30,8 @@ import javax.annotation.Nullable; import org.sonar.api.ExtensionProvider; import org.sonar.api.Plugin; import org.sonar.api.SonarRuntime; +import org.sonar.api.config.Configuration; +import org.sonar.api.internal.PluginContextImpl; import org.sonar.api.utils.AnnotationUtils; import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.PluginInfo; @@ -74,7 +76,10 @@ public abstract class ServerExtensionInstaller { Plugin plugin = pluginRepository.getPluginInstance(pluginKey); container.addExtension(pluginInfo, plugin); - Plugin.Context context = new Plugin.Context(sonarRuntime); + Plugin.Context context = new PluginContextImpl.Builder() + .setSonarRuntime(sonarRuntime) + .setBootConfiguration(container.getComponentByType(Configuration.class)) + .build(); plugin.define(context); for (Object extension : context.getExtensions()) { if (installExtension(container, pluginInfo, extension, true) != null) { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java b/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java index 9dd31141f1e..b52e628f66d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java @@ -22,6 +22,7 @@ package org.sonar.api; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import org.sonar.api.config.Configuration; import org.sonar.api.utils.Version; import static java.util.Arrays.asList; @@ -67,18 +68,22 @@ import static java.util.Objects.requireNonNull; * </project> * * - *

Example of test + *

Example of Test *

  *{@literal @}Test
  * public void test_plugin_extensions_compatible_with_5_6() {
  *   SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(5, 6), SonarQubeSide.SCANNER);
- *   Plugin.Context context = new Plugin.Context(runtime);
- *   new MyPlugin().define(context);
+ *   Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build();
+ *   MyPlugin underTest = new MyPlugin();
+ *
+ *   underTest.define(context);
+ *
  *   assertThat(context.getExtensions()).hasSize(4);
  * }
  * 
* * @since 5.5 + * @see org.sonar.api.internal.PluginContextImpl for unit tests */ public interface Plugin { @@ -86,8 +91,13 @@ public interface Plugin { private final SonarRuntime sonarRuntime; private final List extensions = new ArrayList(); + /** + * For unit tests only. It's recommended to use {@link org.sonar.api.internal.PluginContextImpl.Builder} + * to create instances of {@link Plugin.Context}. + * The configuration returned by {@see #getBootConfiguration()} is empty. + */ public Context(SonarRuntime sonarRuntime) { - this.sonarRuntime = sonarRuntime; + this.sonarRuntime = requireNonNull(sonarRuntime, "sonarRuntime is null"); } /** @@ -152,6 +162,18 @@ public interface Plugin { return extensions; } + /** + * The configuration that contains only the few properties required to bootstrap the process, for example: + * - conf/sonar.properties and persisted properties on web server and Compute Engine sides. The default values + * defined by plugins are ignored. + * - command-line arguments on scanner side. Default values or properties persisted in server are ignored. + * + * @since 7.1 + */ + public Configuration getBootConfiguration() { + throw new UnsupportedOperationException("Unit tests should create Plugin.Context with org.sonar.api.internal.PluginContextImpl#Builder"); + } + } /** diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/internal/PluginContextImpl.java b/sonar-plugin-api/src/main/java/org/sonar/api/internal/PluginContextImpl.java new file mode 100644 index 00000000000..b82c4d8e74c --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/internal/PluginContextImpl.java @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.api.internal; + +import org.sonar.api.Plugin; +import org.sonar.api.SonarRuntime; +import org.sonar.api.config.Configuration; +import org.sonar.api.config.internal.MapSettings; + +/** + * Implementation of {@link Plugin.Context} that plugins could use in their unit tests. + * + * Example: + * + *
+ *   import org.sonar.api.internal.SonarRuntimeImpl;
+ *   import org.sonar.api.config.internal.MapSettings;
+ *
+ *   ...
+ *
+ *   SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 1), SonarQubeSide.SCANNER);
+ *   MapSettings settings = new MapSettings().setProperty("foo", "bar");
+ *   Plugin.Context context = new PluginContextImpl.Builder()
+ *     .setSonarRuntime(runtime)
+ *     .setBootConfiguration(settings.asConfig());
+ *     .build();
+ * 
+ * + * @since 7.1 + */ +public class PluginContextImpl extends Plugin.Context { + + private final Configuration bootConfiguration; + + private PluginContextImpl(Builder builder) { + super(builder.sonarRuntime); + this.bootConfiguration = builder.bootConfiguration != null ? builder.bootConfiguration : new MapSettings().asConfig(); + } + + @Override + public Configuration getBootConfiguration() { + return bootConfiguration; + } + + public static class Builder { + private SonarRuntime sonarRuntime; + private Configuration bootConfiguration; + + /** + * Required. + * @see SonarRuntimeImpl + * @return this + */ + public Builder setSonarRuntime(SonarRuntime r) { + this.sonarRuntime = r; + return this; + } + + /** + * If not set, then an empty configuration is used. + * @return this + */ + public Builder setBootConfiguration(Configuration c) { + this.bootConfiguration = c; + return this; + } + + public Plugin.Context build() { + return new PluginContextImpl(this); + } + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/PluginTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/PluginTest.java index 46bf7131b52..f8b280c40e2 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/PluginTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/PluginTest.java @@ -21,6 +21,8 @@ package org.sonar.api; import java.util.Arrays; import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.internal.PluginContextImpl; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.utils.Version; @@ -33,7 +35,11 @@ public class PluginTest { @Test public void test_context() { SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(VERSION_5_6, SonarQubeSide.SERVER); - Plugin.Context context = new Plugin.Context(runtime); + MapSettings settings = new MapSettings().setProperty("foo", "bar"); + Plugin.Context context = new PluginContextImpl.Builder() + .setSonarRuntime(runtime) + .setBootConfiguration(settings.asConfig()) + .build(); assertThat(context.getSonarQubeVersion()).isEqualTo(VERSION_5_6); assertThat(context.getExtensions()).isEmpty(); @@ -46,5 +52,7 @@ public class PluginTest { context.addExtensions("one", "two", "three", "four"); assertThat(context.getExtensions()).containsOnly("foo", "bar", "baz", "one", "two", "three", "four"); + + assertThat(context.getBootConfiguration().get("foo")).hasValue("bar"); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java index 07abe2ffe3c..25ccc3bfeb0 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java @@ -24,6 +24,8 @@ import javax.annotation.Nullable; import org.sonar.api.ExtensionProvider; import org.sonar.api.Plugin; import org.sonar.api.SonarRuntime; +import org.sonar.api.config.Configuration; +import org.sonar.api.internal.PluginContextImpl; import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginRepository; @@ -33,11 +35,14 @@ public class ExtensionInstaller { private final SonarRuntime sonarRuntime; private final PluginRepository pluginRepository; private final GlobalAnalysisMode analysisMode; + private final Configuration bootConfiguration; - public ExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository, GlobalAnalysisMode analysisMode) { + public ExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository, GlobalAnalysisMode analysisMode, + Configuration bootConfiguration) { this.sonarRuntime = sonarRuntime; this.pluginRepository = pluginRepository; this.analysisMode = analysisMode; + this.bootConfiguration = bootConfiguration; } public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) { @@ -50,7 +55,11 @@ public class ExtensionInstaller { // plugin extensions for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) { Plugin plugin = pluginRepository.getPluginInstance(pluginInfo.getKey()); - Plugin.Context context = new Plugin.Context(sonarRuntime); + Plugin.Context context = new PluginContextImpl.Builder() + .setSonarRuntime(sonarRuntime) + .setBootConfiguration(bootConfiguration) + .build(); + plugin.define(context); for (Object extension : context.getExtensions()) { doInstall(container, matcher, pluginInfo, extension); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ExtensionInstallerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ExtensionInstallerTest.java index 08baf0285ad..09cfc454a41 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ExtensionInstallerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ExtensionInstallerTest.java @@ -22,12 +22,12 @@ package org.sonar.scanner.bootstrap; import java.util.Arrays; import java.util.List; import org.apache.commons.lang.ClassUtils; -import org.junit.Before; import org.junit.Test; import org.sonar.api.BatchExtension; import org.sonar.api.ExtensionProvider; import org.sonar.api.SonarPlugin; import org.sonar.api.SonarRuntime; +import org.sonar.api.config.internal.MapSettings; import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.PluginInfo; @@ -37,8 +37,9 @@ import static org.mockito.Mockito.when; public class ExtensionInstallerTest { - GlobalAnalysisMode mode; - ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class); + private MapSettings settings = new MapSettings(); + private GlobalAnalysisMode mode = mock(GlobalAnalysisMode.class); + private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class); private static SonarPlugin newPluginInstance(final Object... extensions) { return new SonarPlugin() { @@ -48,18 +49,13 @@ public class ExtensionInstallerTest { }; } - @Before - public void setUp() { - mode = mock(GlobalAnalysisMode.class); - } - @Test public void should_filter_extensions_to_install() { when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo"))); when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(Foo.class, Bar.class)); ComponentContainer container = new ComponentContainer(); - ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mock(GlobalAnalysisMode.class)); + ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mode, settings.asConfig()); installer.install(container, new FooMatcher()); assertThat(container.getComponentByType(Foo.class)).isNotNull(); @@ -71,7 +67,7 @@ public class ExtensionInstallerTest { when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo"))); when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(new FooProvider(), new BarProvider())); ComponentContainer container = new ComponentContainer(); - ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mock(GlobalAnalysisMode.class)); + ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mode, settings.asConfig()); installer.install(container, new FooMatcher()); @@ -84,7 +80,7 @@ public class ExtensionInstallerTest { when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo"))); when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(new FooBarProvider())); ComponentContainer container = new ComponentContainer(); - ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mock(GlobalAnalysisMode.class)); + ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mode, settings.asConfig()); installer.install(container, new TrueMatcher());