]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3940 property relocation
authorSimon Brandhof <simon.brandhof@gmail.com>
Wed, 7 Nov 2012 16:30:33 +0000 (17:30 +0100)
committerSimon Brandhof <simon.brandhof@gmail.com>
Wed, 7 Nov 2012 16:30:33 +0000 (17:30 +0100)
sonar-plugin-api/src/main/java/org/sonar/api/Property.java
sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java
sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinitions.java
sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java
sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java
sonar-server/src/main/java/org/sonar/server/platform/Platform.java
sonar-server/src/main/java/org/sonar/server/startup/RenameDeprecatedPropertyKeys.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb [new file with mode: 0644]

index b0179ceedf3ae749711ec7748be26b251288c5db..4802b6fe2514604ecd202fc5693a045517405e31 100644 (file)
@@ -121,4 +121,10 @@ public @interface Property {
    * @since 3.3
    */
   PropertyField[] fields() default {};
+
+  /**
+   * Relocation of key.
+   * @since 3.4
+   */
+  String deprecatedKey() default "";
 }
index c829cd4ac17eda72f27ddba44036a69645b2d4b3..083b598d4dae278ef05088e0742cdd97fe0916dd 100644 (file)
@@ -71,6 +71,7 @@ public final class PropertyDefinition {
   private final boolean isGlobal;
   private final boolean multiValues;
   private final String propertySetKey;
+  private final String deprecatedKey;
   private final List<PropertyFieldDefinition> fields;
 
   private PropertyDefinition(Property annotation) {
@@ -87,6 +88,7 @@ public final class PropertyDefinition {
     this.multiValues = annotation.multiValues();
     this.propertySetKey = annotation.propertySetKey();
     this.fields = ImmutableList.copyOf(PropertyFieldDefinition.create(annotation.fields()));
+    this.deprecatedKey = annotation.deprecatedKey();
   }
 
   private PropertyDefinition(String key, PropertyType type, String[] options) {
@@ -103,6 +105,7 @@ public final class PropertyDefinition {
     this.multiValues = false;
     this.propertySetKey = null;
     this.fields = null;
+    this.deprecatedKey = null;
   }
 
   private static PropertyType fixType(String key, PropertyType type) {
@@ -215,4 +218,11 @@ public final class PropertyDefinition {
   public List<PropertyFieldDefinition> getFields() {
     return fields;
   }
+
+  /**
+   * @since 3.4
+   */
+  public String getDeprecatedKey() {
+    return deprecatedKey;
+  }
 }
index dfd1dfe5b5553a566ea5696bdad6f173bd10cff4..8aae3ed9289feabcd3fa2cc0ccc3f61d1cbf42e0 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.api.config;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
@@ -43,6 +44,9 @@ public final class PropertyDefinitions implements BatchComponent, ServerComponen
   private final Map<String, PropertyDefinition> definitions = Maps.newHashMap();
   private final Map<String, String> categories = Maps.newHashMap();
 
+  // deprecated key -> new key
+  private final Map<String, String> deprecatedKeys = Maps.newHashMap();
+
   public PropertyDefinitions(Object... components) {
     if (components != null) {
       addComponents(Arrays.asList(components));
@@ -87,6 +91,10 @@ public final class PropertyDefinitions implements BatchComponent, ServerComponen
     if (!definitions.containsKey(definition.getKey())) {
       definitions.put(definition.getKey(), definition);
       categories.put(definition.getKey(), StringUtils.defaultIfBlank(definition.getCategory(), defaultCategory));
+      if (!Strings.isNullOrEmpty(definition.getDeprecatedKey()) && !definition.getDeprecatedKey().equals(definition.getKey())) {
+        deprecatedKeys.put(definition.getDeprecatedKey(), definition.getKey());
+        definitions.put(definition.getDeprecatedKey(), definition);
+      }
     }
     return this;
   }
@@ -170,4 +178,16 @@ public final class PropertyDefinitions implements BatchComponent, ServerComponen
   public String getCategory(Property prop) {
     return getCategory(prop.key());
   }
+
+  public String getNewKey(String deprecatedKey) {
+    return deprecatedKeys.get(deprecatedKey);
+  }
+
+  public String getDeprecatedKey(String key) {
+    PropertyDefinition def = get(key);
+    if (def == null) {
+      return null;
+    }
+    return StringUtils.defaultIfEmpty(def.getDeprecatedKey(), null);
+  }
 }
index 8043a7e9e354b93b4a92aaf21204e29f41682adf..a3a087b417518d5669be1fd3f54511fc123a0382 100644 (file)
@@ -92,10 +92,8 @@ public class Settings implements BatchComponent, ServerComponent {
   }
 
   public final String getString(String key) {
-    String value = properties.get(key);
-    if (value == null) {
-      value = getDefaultValue(key);
-    } else if (encryption.isEncrypted(value)) {
+    String value = getClearString(key);
+    if (value != null && encryption.isEncrypted(value)) {
       try {
         value = encryption.decrypt(value);
       } catch (Exception e) {
@@ -264,10 +262,8 @@ public class Settings implements BatchComponent, ServerComponent {
       throw new IllegalStateException("Fail to set multiple values on a single value property " + key);
     }
 
-    if (values == null) {
-      properties.remove(key);
-      doOnRemoveProperty(key);
-    } else {
+    String text = null;
+    if (values != null) {
       List<String> escaped = Lists.newArrayList();
       for (String value : values) {
         if (null != value) {
@@ -278,13 +274,16 @@ public class Settings implements BatchComponent, ServerComponent {
       }
 
       String escapedValue = Joiner.on(',').join(escaped);
-      properties.put(key, StringUtils.trim(escapedValue));
-      doOnSetProperty(key, escapedValue);
+      text = StringUtils.trim(escapedValue);
     }
-    return this;
+    return setProperty(key, text);
   }
 
   public final Settings setProperty(String key, @Nullable String value) {
+    return setProperty(key, value, true);
+  }
+
+  private Settings setProperty(String key, @Nullable String value, boolean recursive) {
     if (value == null) {
       properties.remove(key);
       doOnRemoveProperty(key);
@@ -292,6 +291,17 @@ public class Settings implements BatchComponent, ServerComponent {
       properties.put(key, StringUtils.trim(value));
       doOnSetProperty(key, value);
     }
+    if (recursive) {
+      String newKey = definitions.getNewKey(key);
+      if (newKey != null) {
+        setProperty(newKey, value, false);
+      } else {
+        String deprecatedKey = definitions.getDeprecatedKey(key);
+        if (deprecatedKey != null) {
+          setProperty(deprecatedKey, value, false);
+        }
+      }
+    }
     return this;
   }
 
@@ -347,7 +357,7 @@ public class Settings implements BatchComponent, ServerComponent {
   }
 
   public final Settings setProperties(Settings s) {
-    if (s.properties==null) {
+    if (s.properties == null) {
       return clear();
     }
     return setProperties(Maps.newHashMap(s.properties));
index 8be0edeca61b2837edb5ad6f151024b66b2a979c..0993b09063fdc6d9d47f4fb03d3d934e52e844f2 100644 (file)
@@ -44,7 +44,10 @@ public class SettingsTest {
     @Property(key = "integer", name = "Integer", defaultValue = "12345"),
     @Property(key = "array", name = "Array", defaultValue = "one,two,three"),
     @Property(key = "multi_values", name = "Array", defaultValue = "1,2,3", multiValues = true),
-    @Property(key = "sonar.jira", name = "Jira Server", type = PropertyType.PROPERTY_SET, propertySetKey = "jira")
+    @Property(key = "sonar.jira", name = "Jira Server", type = PropertyType.PROPERTY_SET, propertySetKey = "jira"),
+    @Property(key = "newKey", name = "New key", deprecatedKey = "oldKey"),
+    @Property(key = "newKeyWithDefaultValue", name = "New key with default value", deprecatedKey = "oldKeyWithDefaultValue", defaultValue = "default_value"),
+    @Property(key = "new_multi_values", name = "New multi values", defaultValue = "1,2,3", multiValues = true, deprecatedKey = "old_multi_values")
   })
   static class Init {
   }
@@ -376,4 +379,39 @@ public class SettingsTest {
     assertThat(settings.getKeysStartingWith("sonar.jdbc")).containsOnly("sonar.jdbc.url", "sonar.jdbc.username");
     assertThat(settings.getKeysStartingWith("other")).hasSize(0);
   }
+
+  @Test
+  public void should_fallback_deprecated_key_to_default_value_of_new_key() {
+    Settings settings = new Settings(definitions);
+
+    assertThat(settings.getString("newKeyWithDefaultValue")).isEqualTo("default_value");
+    assertThat(settings.getString("oldKeyWithDefaultValue")).isEqualTo("default_value");
+  }
+
+  @Test
+  public void should_fallback_deprecated_key_to_new_key() {
+    Settings settings = new Settings(definitions);
+    settings.setProperty("newKey", "value of newKey");
+
+    assertThat(settings.getString("newKey")).isEqualTo("value of newKey");
+    assertThat(settings.getString("oldKey")).isEqualTo("value of newKey");
+  }
+
+  @Test
+  public void should_load_value_set_on_deprecated_key() {
+    // it's used for example when deprecated settings are set through command-line
+    Settings settings = new Settings(definitions);
+    settings.setProperty("oldKey", "value of oldKey");
+
+    assertThat(settings.getString("newKey")).isEqualTo("value of oldKey");
+    assertThat(settings.getString("oldKey")).isEqualTo("value of oldKey");
+  }
+
+  @Test
+  public void should_support_deprecated_props_with_multi_values() {
+    Settings settings = new Settings(definitions);
+    settings.setProperty("new_multi_values", new String[]{" A ", " B "});
+    assertThat(settings.getStringArray("new_multi_values")).isEqualTo(new String[]{"A", "B"});
+    assertThat(settings.getStringArray("old_multi_values")).isEqualTo(new String[]{"A", "B"});
+  }
 }
index b47b65ba5e321d2035bfe50c5f70dcd6a9bbc448..5c5d8f4695509becce1c05dfb0df08f17feee15a 100644 (file)
@@ -89,6 +89,7 @@ import org.sonar.server.startup.RegisterNewFilters;
 import org.sonar.server.startup.RegisterNewProfiles;
 import org.sonar.server.startup.RegisterQualityModels;
 import org.sonar.server.startup.RegisterRules;
+import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
 import org.sonar.server.startup.ServerMetadataPersister;
 import org.sonar.server.ui.CodeColorizers;
 import org.sonar.server.ui.JRubyI18n;
@@ -269,6 +270,7 @@ public final class Platform {
     startupContainer.addSingleton(GeneratePluginIndex.class);
     startupContainer.addSingleton(RegisterNewFilters.class);
     startupContainer.addSingleton(RegisterNewDashboards.class);
+    startupContainer.addSingleton(RenameDeprecatedPropertyKeys.class);
     startupContainer.startComponents();
 
     startupContainer.getComponentByType(ServerLifecycleNotifier.class).notifyStart();
index 6e154c7144e8915e36e379a420560e60e5507dda..79c70a8f0f07ba4715fc4c8c87bd6c677a65d615 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.startup;
 
 import com.google.common.base.Strings;
+import org.slf4j.LoggerFactory;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.core.properties.PropertiesDao;
@@ -38,6 +39,7 @@ public class RenameDeprecatedPropertyKeys {
   }
 
   public void start() {
+    LoggerFactory.getLogger(RenameDeprecatedPropertyKeys.class).info("Rename deprecated property keys");
     for (PropertyDefinition definition : definitions.getAll()) {
       if (!Strings.isNullOrEmpty(definition.getDeprecatedKey())) {
         dao.renamePropertyKey(definition.getDeprecatedKey(), definition.getKey());
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/measures_controller.rb
new file mode 100644 (file)
index 0000000..0b6662b
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# 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
+#
+class MeasuresController < ApplicationController
+
+  def index
+    
+  end
+
+
+end