From 875e23e29f4ed2d41146d8bba8b22448b23df113 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Thu, 29 Jun 2017 15:08:28 +0200 Subject: SONAR-9478 Deprecate Settings and introduce new Configuration interface --- .../java/org/sonar/api/config/Configuration.java | 183 +++++++++++++++++++++ .../java/org/sonar/api/config/EmailSettings.java | 4 - .../java/org/sonar/api/config/MapSettings.java | 75 --------- .../org/sonar/api/config/PropertyDefinition.java | 2 +- .../org/sonar/api/config/PropertyDefinitions.java | 1 + .../main/java/org/sonar/api/config/Settings.java | 60 +------ .../api/config/internal/ConfigurationBridge.java | 52 ++++++ .../org/sonar/api/config/internal/MapSettings.java | 89 ++++++++++ .../sonar/api/config/internal/package-info.java | 23 +++ 9 files changed, 354 insertions(+), 135 deletions(-) create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/Configuration.java delete mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/MapSettings.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/internal/ConfigurationBridge.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/internal/MapSettings.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/config/internal/package-info.java (limited to 'sonar-plugin-api/src/main/java/org/sonar/api/config') diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/Configuration.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/Configuration.java new file mode 100644 index 00000000000..f91996a0734 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/Configuration.java @@ -0,0 +1,183 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.config; + +import java.util.Optional; +import org.sonar.api.batch.ScannerSide; +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.server.ServerSide; +import org.sonarsource.api.sonarlint.SonarLintSide; + +/** + * Component to get effective configuration. Values of properties depend on the runtime environment: + * + * + *

Usage

+ *
+ * public class MyExtension {
+ *
+ *   private final Configuration config;
+ *
+ *   public MyExtension(Configuration config) {
+ *     this.config = config;
+ *   }
+ *   public void doSomething() {
+ *     String fooValue = config.get("sonar.foo").orElse(null);
+ *     // ..
+ *   }
+ * }
+ * 
+ * + *

Scanner example

+ * Scanner sensor can get the reference on Configuration directly through SensorContext, + * without injecting the component into constructor. + * + *
+ * public class MySensor implements Sensor {
+ *   {@literal @}Override
+ *   public void execute(SensorContext context) {
+ *     String fooValue = context.config().get("sonar.foo").orElse(null);
+ *     // ..
+ *   }
+ * }
+ * 
+ * + *

+ * For testing, and only for testing, the in-memory implementation {@link MapSettings} can be used. + *

+ * {@literal @}Test
+ * public void my_test() {
+ *   MapSettings settings = new MapSettings();
+ *   settings.setProperty("foo", "bar");
+ *   MyExtension underTest = new MyExtension(settings.asConfig());
+ *   // ...
+ * }
+ * 
+ * + * @see MapSettings + * @see PropertyDefinition + * @since 6.5 + */ +@ScannerSide +@ServerSide +@ComputeEngineSide +@SonarLintSide +public interface Configuration { + + /** + * The effective value of the specified property. Can return {@code Optional#empty()} if the property is not set and has no defined default value. + *

+ * If the property is encrypted with a secret key, then the returned value is decrypted. + *

+ * + * @throws IllegalStateException if value is encrypted but fails to be decrypted. + */ + Optional get(String key); + + /** + * @return {@code true} if the property has a non-default value, else {@code false}. + */ + boolean hasKey(String key); + + /** + * Used to read multi-valued properties. + *

+ * See {@link PropertyDefinition.Builder#multiValues(boolean)} + * Multi-valued properties coming from scanner are parsed as CSV lines (ie comma separator and optional double quotes to escape values). + * Non quoted values are trimmed. + *
+ * Examples : + *

+ */ + String[] getStringArray(String key); + + /** + * Effective value as boolean. It is {@code empty} if {@link #get(String)} is empty or if it + * does not return {@code "true"}, even if it's not a boolean representation. + * @return {@code true} if the effective value is {@code "true"}, {@code false} for any other non empty value. + * If the property does not have value nor default value, then {@code empty} is returned. + */ + default Optional getBoolean(String key) { + return get(key).map(Boolean::parseBoolean); + } + + /** + * Effective value as {@code int}. + * @return the value as {@code int}. If the property does not have value nor default value, then {@code empty} is returned. + * @throws NumberFormatException if value is not empty and is not a parsable integer + */ + default Optional getInt(String key) { + try { + return get(key).map(Integer::parseInt); + } catch (NumberFormatException e) { + throw new IllegalStateException(String.format("The property '%s' is not an int value: %s", key, e.getMessage())); + } + } + + /** + * Effective value as {@code long}. + * @return the value as {@code long}. If the property does not have value nor default value, then {@code empty} is returned. + * @throws NumberFormatException if value is not empty and is not a parsable {@code long} + */ + default Optional getLong(String key) { + try { + return get(key).map(Long::parseLong); + } catch (NumberFormatException e) { + throw new IllegalStateException(String.format("The property '%s' is not an long value: %s", key, e.getMessage())); + } + } + + /** + * Effective value as {@code Float}. + * @return the value as {@code Float}. If the property does not have value nor default value, then {@code empty} is returned. + * @throws NumberFormatException if value is not empty and is not a parsable number + */ + default Optional getFloat(String key) { + try { + return get(key).map(Float::valueOf); + } catch (NumberFormatException e) { + throw new IllegalStateException(String.format("The property '%s' is not an float value: %s", key, e.getMessage())); + } + } + + /** + * Effective value as {@code Double}. + * @return the value as {@code Double}. If the property does not have value nor default value, then {@code empty} is returned. + * @throws NumberFormatException if value is not empty and is not a parsable number + */ + default Optional getDouble(String key) { + try { + return get(key).map(Double::valueOf); + } catch (NumberFormatException e) { + throw new IllegalStateException(String.format("The property '%s' is not an double value: %s", key, e.getMessage())); + } + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/EmailSettings.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/EmailSettings.java index dc449884522..dae2594593a 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/EmailSettings.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/EmailSettings.java @@ -21,7 +21,6 @@ package org.sonar.api.config; import java.util.List; import org.sonar.api.PropertyType; -import org.sonar.api.batch.ScannerSide; import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.server.ServerSide; @@ -34,11 +33,8 @@ import static org.sonar.api.PropertyType.INTEGER; import static org.sonar.api.PropertyType.SINGLE_SELECT_LIST; /** - * If batch extensions use this component, then batch must be executed with administrator rights (see properties sonar.login and sonar.password) - * * @since 3.2 */ -@ScannerSide @ServerSide @ComputeEngineSide public class EmailSettings { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/MapSettings.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/MapSettings.java deleted file mode 100644 index 5a73567a808..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/MapSettings.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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.config; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import static java.util.Collections.unmodifiableMap; - -/** - * In-memory map-based implementation of {@link Settings}. It must be used - * only for unit tests. This is not the implementation - * deployed at runtime, so non-test code must never cast - * {@link Settings} to {@link MapSettings}. - * - * @since 6.1 - */ -public class MapSettings extends Settings { - - private final Map props = new HashMap<>(); - - public MapSettings() { - super(new PropertyDefinitions(), new Encryption(null)); - } - - public MapSettings(PropertyDefinitions definitions) { - super(definitions, new Encryption(null)); - } - - @Override - protected Optional get(String key) { - return Optional.ofNullable(props.get(key)); - } - - @Override - protected void set(String key, String value) { - props.put(key, value); - } - - @Override - protected void remove(String key) { - props.remove(key); - } - - @Override - public Map getProperties() { - return unmodifiableMap(props); - } - - /** - * Delete all properties - */ - public MapSettings clear() { - props.clear(); - return this; - } -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java index 02d64853e8e..13c407d000b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java @@ -57,7 +57,7 @@ import static org.sonar.api.PropertyType.REGULAR_EXPRESSION; import static org.sonar.api.PropertyType.SINGLE_SELECT_LIST; /** - * Declare a plugin property. Values are available at runtime through the component {@link Settings}. + * Declare a plugin property. Values are available at runtime through the components {@link Settings} or {@link org.sonar.api.Configuration.SettingsReader}. *
* It's the programmatic alternative to the annotation {@link org.sonar.api.Property}. It is more * testable and adds new features like sub-categories and ordering. diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java index 9a0834b62be..b0e5275674f 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java @@ -165,6 +165,7 @@ public final class PropertyDefinitions { return byCategory; } + @CheckForNull public String getDefaultValue(String key) { PropertyDefinition def = get(key); if (def == null) { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java index 7e182dcd555..20fb15bff45 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java @@ -35,69 +35,19 @@ import org.sonar.api.batch.ScannerSide; import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.server.ServerSide; import org.sonar.api.utils.DateUtils; +import org.sonarsource.api.sonarlint.SonarLintSide; import static java.util.Objects.requireNonNull; import static org.apache.commons.lang.StringUtils.trim; /** - * Component to get effective settings. Values of properties depend on the runtime environment: - *
    - *
  • project settings in scanner.
  • - *
  • global settings in web server. It does not allow to get the settings overridden on projects.
  • - *
  • project settings in Compute Engine.
  • - *
- * - *

Usage

- *
- * public class MyExtension {
- *
- *   private final Settings settings;
- *
- *   public MyExtension(Settings settings) {
- *     this.settings = settings;
- *   }
- *   public void doSomething() {
- *     String fooValue = settings.getString("sonar.foo");
- *     // ..
- *   }
- * }
- * 
- * - *

Scanner example

- * Scanner sensor can get the reference on Settings directly through SensorContext, - * without injecting the component into constructor. - * - *
- * public class MySensor implements Sensor {
- *   {@literal @}Override
- *   public void execute(SensorContext context) {
- *     String fooValue = context.settings().getString("sonar.foo");
- *     // ..
- *   }
- * }
- * 
- * - *

- * For testing, and only for testing, the in-memory implementation {@link MapSettings} can be used. - *

- * {@literal @}Test
- * public void my_test() {
- *   Settings settings = new MapSettings();
- *   settings.setProperty("foo", "bar");
- *   MyExtension underTest = new MyExtension(settings);
- *   // ...
- * }
- * 
- * - * History - this class is abstract since 6.1. - * - * @see MapSettings - * @see PropertyDefinition - * @since 2.12 + * @deprecated since 6.5 use {@link Configuration} */ -@ScannerSide @ServerSide @ComputeEngineSide +@ScannerSide +@SonarLintSide +@Deprecated public abstract class Settings { private final PropertyDefinitions definitions; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/ConfigurationBridge.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/ConfigurationBridge.java new file mode 100644 index 00000000000..4e8ef584fd3 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/ConfigurationBridge.java @@ -0,0 +1,52 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.config.internal; + +import java.util.Optional; +import org.sonar.api.config.Settings; +import org.sonar.api.config.Configuration; + +/** + * Used to help migration from {@link Settings} to {@link Configuration} + */ +public class ConfigurationBridge implements Configuration { + + private final Settings settings; + + public ConfigurationBridge(Settings settings) { + this.settings = settings; + } + + @Override + public Optional get(String key) { + return Optional.ofNullable(settings.getString(key)); + } + + @Override + public boolean hasKey(String key) { + return settings.hasKey(key); + } + + @Override + public String[] getStringArray(String key) { + return settings.getStringArray(key); + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/MapSettings.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/MapSettings.java new file mode 100644 index 00000000000..6d45e12ddb6 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/MapSettings.java @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.config.internal; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import org.sonar.api.config.Configuration; +import org.sonar.api.config.Encryption; +import org.sonar.api.config.PropertyDefinitions; +import org.sonar.api.config.Settings; + +import static java.util.Collections.unmodifiableMap; + +/** + * In-memory map-based implementation of {@link Settings}. It must be used + * only for unit tests. This is not the implementation + * deployed at runtime, so non-test code must never cast + * {@link Settings} to {@link MapSettings}. + * + * @since 6.1 + */ +public class MapSettings extends Settings { + + private final Map props = new HashMap<>(); + private final ConfigurationBridge configurationBridge; + + public MapSettings() { + this(new PropertyDefinitions()); + } + + public MapSettings(PropertyDefinitions definitions) { + super(definitions, new Encryption(null)); + configurationBridge = new ConfigurationBridge(this); + } + + @Override + protected Optional get(String key) { + return Optional.ofNullable(props.get(key)); + } + + @Override + protected void set(String key, String value) { + props.put(key, value); + } + + @Override + protected void remove(String key) { + props.remove(key); + } + + @Override + public Map getProperties() { + return unmodifiableMap(props); + } + + /** + * Delete all properties + */ + public MapSettings clear() { + props.clear(); + return this; + } + + /** + * @return a {@link Configuration} proxy on top of this existing {@link Settings} implementation. Changes are reflected in the {@link Configuration} object. + * @since 6.5 + */ + public Configuration asConfig() { + return configurationBridge; + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/package-info.java new file mode 100644 index 00000000000..4fb297e0a30 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/internal/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.api.config.internal; + +import javax.annotation.ParametersAreNonnullByDefault; -- cgit v1.2.3