diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2012-03-16 11:46:48 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2012-03-16 11:50:43 +0100 |
commit | f6a1da456075b5307537c9f736eecb656c5d3a2d (patch) | |
tree | 66d1d3bd84833af3ba30572629637ba69537791f | |
parent | ab19fa283c7c86034ebde4823b3b8675797d9fbb (diff) | |
download | sonarqube-f6a1da456075b5307537c9f736eecb656c5d3a2d.tar.gz sonarqube-f6a1da456075b5307537c9f736eecb656c5d3a2d.zip |
SONAR-1378 validate property types + update type of core properties
30 files changed, 803 insertions, 413 deletions
diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstylePlugin.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstylePlugin.java index 515b8d15e04..9bba008989b 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstylePlugin.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstylePlugin.java @@ -21,6 +21,7 @@ package org.sonar.plugins.checkstyle; import org.sonar.api.Properties; import org.sonar.api.Property; +import org.sonar.api.PropertyType; import org.sonar.api.SonarPlugin; import java.util.Arrays; @@ -35,7 +36,7 @@ import java.util.List; + " See <a href='http://checkstyle.sourceforge.net/config.html'>Checkstyle configuration page</a> to get more information on those filters.", project = false, global = true, - type = Property.Type.TEXT)}) + type = PropertyType.TEXT)}) public final class CheckstylePlugin extends SonarPlugin { public List getExtensions() { diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index b0d273c9fe6..71c09d25209 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -20,11 +20,9 @@ package org.sonar.plugins.core; import com.google.common.collect.Lists; -import org.sonar.api.CoreProperties; -import org.sonar.api.Properties; -import org.sonar.api.Property; -import org.sonar.api.SonarPlugin; +import org.sonar.api.*; import org.sonar.api.checks.NoSonarFilter; +import org.sonar.api.PropertyType; import org.sonar.api.resources.Java; import org.sonar.plugins.core.batch.ExcludedResourceFilter; import org.sonar.plugins.core.batch.IndexProjectPostJob; @@ -50,177 +48,177 @@ import org.sonar.plugins.core.widgets.reviews.*; import java.util.List; @Properties({ - @Property( - key = CoreProperties.SERVER_BASE_URL, - defaultValue = CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE, - name = "Server base URL", - description = "HTTP URL of this Sonar server, such as <i>http://yourhost.yourdomain/sonar</i>. This value is used i.e. to create links in emails.", - project = false, - global = true, - category = CoreProperties.CATEGORY_GENERAL), - @Property( - key = CoreProperties.CORE_COVERAGE_PLUGIN_PROPERTY, - defaultValue = "cobertura", - name = "Code coverage plugin", - description = "Key of the code coverage plugin to use.", - project = true, - global = true, - category = CoreProperties.CATEGORY_CODE_COVERAGE), - @Property( - key = CoreProperties.CORE_IMPORT_SOURCES_PROPERTY, - defaultValue = "" + CoreProperties.CORE_IMPORT_SOURCES_DEFAULT_VALUE, - name = "Import sources", - description = "Set to false if sources should not be displayed, e.g. for security reasons.", - project = true, - module = true, - global = true, - category = CoreProperties.CATEGORY_SECURITY, - type = Property.Type.BOOLEAN), - @Property( - key = CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, - defaultValue = "" + CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE, - name = "Tendency period", - description = TendencyDecorator.PROP_DAYS_DESCRIPTION, - project = false, - global = true, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, - type = Property.Type.INTEGER), - @Property( - key = CoreProperties.SKIP_TENDENCIES_PROPERTY, - defaultValue = "" + CoreProperties.SKIP_TENDENCIES_DEFAULT_VALUE, - name = "Skip tendencies", - description = "Skip calculation of measure tendencies", - project = true, - module = false, - global = true, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, - type = Property.Type.BOOLEAN), - @Property( - key = CoreProperties.CORE_SKIPPED_MODULES_PROPERTY, - name = "Exclude modules", - description = "Maven artifact ids of modules to exclude (comma-separated).", - project = true, - global = false, - category = CoreProperties.CATEGORY_GENERAL), - @Property( - key = CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, - defaultValue = "" + CoreProperties.CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE, - name = "Force user authentication", - description = "Forcing user authentication stops un-logged users to access Sonar.", - project = false, - global = true, - category = CoreProperties.CATEGORY_SECURITY, - type = Property.Type.BOOLEAN), - @Property( - key = CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_PROPERTY, - defaultValue = "" + CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_DEAULT_VALUE, - name = "Allow users to sign up online", - description = "Users can sign up online.", - project = false, - global = true, - category = CoreProperties.CATEGORY_SECURITY, - type = Property.Type.BOOLEAN), - @Property( - key = CoreProperties.CORE_DEFAULT_GROUP, - defaultValue = CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE, - name = "Default user group", - description = "Any new users will automatically join this group.", - project = false, - global = true, - category = CoreProperties.CATEGORY_SECURITY), - @Property( - key = CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY, - defaultValue = "en", - name = "Locale used for violation messages", - description = "Locale to be used when generating violation messages. It's up to each rule engine to support this global internationalization property", - project = true, - global = true, - category = CoreProperties.CATEGORY_L10N), - @Property( - key = "sonar.timemachine.period1", - name = "Period 1", - description = "Period used to compare measures and track new violations. Values are : <ul class='bullet'><li>Number of days before " + - "analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, for example 2010-12-25</li><li>'previous_analysis' to " + - "compare to previous analysis</li></ul>" + - "Changing this property only take effect after subsequent project inspections.", - project = false, - global = true, - defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_1, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), - @Property( - key = "sonar.timemachine.period2", - name = "Period 2", - description = "See the property 'Period 1'", - project = false, - global = true, - defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_2, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), - @Property( - key = "sonar.timemachine.period3", - name = "Period 3", - description = "See the property 'Period 1'", - project = false, - global = true, - defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_3, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), - @Property( - key = "sonar.timemachine.period4", - name = "Period 4", - description = "Period used to compare measures and track new violations. This property is specific to the project. Values are : " + - "<ul class='bullet'><li>Number of days before analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, " + - "for example 2010-12-25</li><li>'previous_analysis' to compare to previous analysis</li><li>A version, for example 1.2</li></ul>" + - "Changing this property only take effect after subsequent project inspection.", - project = true, - global = false, - defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_4, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), - @Property( - key = "sonar.timemachine.period5", - name = "Period 5", - description = "See the property 'Period 4'", - project = true, - global = false, - defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_5, - category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), + @Property( + key = CoreProperties.SERVER_BASE_URL, + defaultValue = CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE, + name = "Server base URL", + description = "HTTP URL of this Sonar server, such as <i>http://yourhost.yourdomain/sonar</i>. This value is used i.e. to create links in emails.", + project = false, + global = true, + category = CoreProperties.CATEGORY_GENERAL), + @Property( + key = CoreProperties.CORE_COVERAGE_PLUGIN_PROPERTY, + defaultValue = "cobertura", + name = "Code coverage plugin", + description = "Key of the code coverage plugin to use.", + project = true, + global = true, + category = CoreProperties.CATEGORY_CODE_COVERAGE), + @Property( + key = CoreProperties.CORE_IMPORT_SOURCES_PROPERTY, + defaultValue = "" + CoreProperties.CORE_IMPORT_SOURCES_DEFAULT_VALUE, + name = "Import sources", + description = "Set to false if sources should not be displayed, e.g. for security reasons.", + project = true, + module = true, + global = true, + category = CoreProperties.CATEGORY_SECURITY, + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, + defaultValue = "" + CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE, + name = "Tendency period", + description = TendencyDecorator.PROP_DAYS_DESCRIPTION, + project = false, + global = true, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, + type = PropertyType.INTEGER), + @Property( + key = CoreProperties.SKIP_TENDENCIES_PROPERTY, + defaultValue = "" + CoreProperties.SKIP_TENDENCIES_DEFAULT_VALUE, + name = "Skip tendencies", + description = "Skip calculation of measure tendencies", + project = true, + module = false, + global = true, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CORE_SKIPPED_MODULES_PROPERTY, + name = "Exclude modules", + description = "Maven artifact ids of modules to exclude (comma-separated).", + project = true, + global = false, + category = CoreProperties.CATEGORY_GENERAL), + @Property( + key = CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, + defaultValue = "" + CoreProperties.CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE, + name = "Force user authentication", + description = "Forcing user authentication stops un-logged users to access Sonar.", + project = false, + global = true, + category = CoreProperties.CATEGORY_SECURITY, + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_PROPERTY, + defaultValue = "" + CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_DEAULT_VALUE, + name = "Allow users to sign up online", + description = "Users can sign up online.", + project = false, + global = true, + category = CoreProperties.CATEGORY_SECURITY, + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CORE_DEFAULT_GROUP, + defaultValue = CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE, + name = "Default user group", + description = "Any new users will automatically join this group.", + project = false, + global = true, + category = CoreProperties.CATEGORY_SECURITY), + @Property( + key = CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY, + defaultValue = "en", + name = "Locale used for violation messages", + description = "Locale to be used when generating violation messages. It's up to each rule engine to support this global internationalization property", + project = true, + global = true, + category = CoreProperties.CATEGORY_L10N), + @Property( + key = "sonar.timemachine.period1", + name = "Period 1", + description = "Period used to compare measures and track new violations. Values are : <ul class='bullet'><li>Number of days before " + + "analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, for example 2010-12-25</li><li>'previous_analysis' to " + + "compare to previous analysis</li></ul>" + + "Changing this property only take effect after subsequent project inspections.", + project = false, + global = true, + defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_1, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), + @Property( + key = "sonar.timemachine.period2", + name = "Period 2", + description = "See the property 'Period 1'", + project = false, + global = true, + defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_2, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), + @Property( + key = "sonar.timemachine.period3", + name = "Period 3", + description = "See the property 'Period 1'", + project = false, + global = true, + defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_3, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), + @Property( + key = "sonar.timemachine.period4", + name = "Period 4", + description = "Period used to compare measures and track new violations. This property is specific to the project. Values are : " + + "<ul class='bullet'><li>Number of days before analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, " + + "for example 2010-12-25</li><li>'previous_analysis' to compare to previous analysis</li><li>A version, for example 1.2</li></ul>" + + "Changing this property only take effect after subsequent project inspection.", + project = true, + global = false, + defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_4, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), + @Property( + key = "sonar.timemachine.period5", + name = "Period 5", + description = "See the property 'Period 4'", + project = true, + global = false, + defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_5, + category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), - // SERVER-SIDE TECHNICAL PROPERTIES + // SERVER-SIDE TECHNICAL PROPERTIES - @Property( - key = "sonar.security.realm", - name = "Security Realm", - project = false, - global = false - ), - @Property( - key = "sonar.security.savePassword", - name = "Save external password", - project = false, - global = false - ), - @Property( - key = "sonar.authenticator.downcase", - name = "Downcase login", - description = "Downcase login during user authentication, typically for Active Directory", - project = false, - global = false, - defaultValue = "false", - type = Property.Type.BOOLEAN), - @Property( - key = CoreProperties.CORE_AUTHENTICATOR_CREATE_USERS, - name = "Create user accounts", - description = "Create accounts when authenticating users via an external system", - project = false, - global = false, - defaultValue = "true", - type = Property.Type.BOOLEAN), - @Property( - key = CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, - name = "Ignore failures during authenticator startup", - defaultValue = "false", - project = false, - global = false, - type = Property.Type.BOOLEAN) + @Property( + key = "sonar.security.realm", + name = "Security Realm", + project = false, + global = false + ), + @Property( + key = "sonar.security.savePassword", + name = "Save external password", + project = false, + global = false + ), + @Property( + key = "sonar.authenticator.downcase", + name = "Downcase login", + description = "Downcase login during user authentication, typically for Active Directory", + project = false, + global = false, + defaultValue = "false", + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CORE_AUTHENTICATOR_CREATE_USERS, + name = "Create user accounts", + description = "Create accounts when authenticating users via an external system", + project = false, + global = false, + defaultValue = "true", + type = PropertyType.BOOLEAN), + @Property( + key = CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, + name = "Ignore failures during authenticator startup", + defaultValue = "false", + project = false, + global = false, + type = PropertyType.BOOLEAN) }) public final class CorePlugin extends SonarPlugin { diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java index ddefdb4fa4c..2708f843d17 100644 --- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java +++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java @@ -19,10 +19,8 @@ */ package org.sonar.plugins.cpd; -import org.sonar.api.CoreProperties; -import org.sonar.api.Properties; -import org.sonar.api.Property; -import org.sonar.api.SonarPlugin; +import org.sonar.api.*; +import org.sonar.api.PropertyType; import org.sonar.plugins.cpd.decorators.DuplicationDensityDecorator; import org.sonar.plugins.cpd.decorators.SumDuplicationsDecorator; import org.sonar.plugins.cpd.index.IndexFactory; @@ -43,7 +41,7 @@ import java.util.List; module = true, global = true, category = CoreProperties.CATEGORY_DUPLICATIONS, - type = Property.Type.SINGLE_SELECT_LIST, + type = PropertyType.SINGLE_SELECT_LIST, options = {"sonar", "pmd"}), @Property( key = CoreProperties.CPD_CROSS_RPOJECT, @@ -56,7 +54,7 @@ import java.util.List; module = true, global = true, category = CoreProperties.CATEGORY_DUPLICATIONS, - type = Property.Type.BOOLEAN), + type = PropertyType.BOOLEAN), @Property( key = CoreProperties.CPD_MINIMUM_TOKENS_PROPERTY, defaultValue = CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE + "", @@ -67,7 +65,7 @@ import java.util.List; module = true, global = true, category = CoreProperties.CATEGORY_DUPLICATIONS, - type = Property.Type.INTEGER), + type = PropertyType.INTEGER), @Property( key = CoreProperties.CPD_IGNORE_LITERALS_PROPERTY, defaultValue = CoreProperties.CPD_IGNORE_LITERALS_DEFAULT_VALUE + "", @@ -79,7 +77,7 @@ import java.util.List; module = true, global = true, category = CoreProperties.CATEGORY_DUPLICATIONS, - type = Property.Type.BOOLEAN), + type = PropertyType.BOOLEAN), @Property( key = CoreProperties.CPD_IGNORE_IDENTIFIERS_PROPERTY, defaultValue = CoreProperties.CPD_IGNORE_IDENTIFIERS_DEFAULT_VALUE + "", @@ -90,7 +88,7 @@ import java.util.List; module = true, global = true, category = CoreProperties.CATEGORY_DUPLICATIONS, - type = Property.Type.BOOLEAN) + type = PropertyType.BOOLEAN) }) public final class CpdPlugin extends SonarPlugin { diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java index 15a74fa8768..4507771468f 100644 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java @@ -21,6 +21,7 @@ package org.sonar.plugins.dbcleaner; import org.sonar.api.Properties; import org.sonar.api.Property; +import org.sonar.api.PropertyType; import org.sonar.api.SonarPlugin; import org.sonar.plugins.dbcleaner.api.DbCleanerConstants; import org.sonar.plugins.dbcleaner.period.DefaultPeriodCleaner; @@ -35,20 +36,20 @@ import java.util.List; + "the DbCleaner keeps the first one and fully delete the other ones.", global = true, project = true, - type = Property.Type.INTEGER), + type = PropertyType.INTEGER), @Property(key = DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH, defaultValue = "52", name = "Number of weeks before starting to keep only one snapshot by month", description = "After this number of weeks, if there are several snapshots during the same month, " + "the DbCleaner keeps the first one and fully delete the other ones.", global = true, project = true, - type = Property.Type.INTEGER), + type = PropertyType.INTEGER), @Property(key = DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS, defaultValue = "260", name = "Number of weeks before starting to delete all remaining snapshots", description = "After this number of weeks, all snapshots are fully deleted.", global = true, project = true, - type = Property.Type.INTEGER) + type = PropertyType.INTEGER) } ) public final class DbCleanerPlugin extends SonarPlugin { diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DefaultPurgeTask.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DefaultPurgeTask.java index 6fe63815b53..afee357487a 100644 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DefaultPurgeTask.java +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DefaultPurgeTask.java @@ -23,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.Properties; import org.sonar.api.Property; +import org.sonar.api.PropertyType; import org.sonar.api.config.Settings; import org.sonar.api.resources.Scopes; import org.sonar.core.purge.PurgeDao; @@ -41,7 +42,7 @@ import org.sonar.plugins.dbcleaner.period.DefaultPeriodCleaner; global = true, project = true, module = false, - type = Property.Type.BOOLEAN) + type = PropertyType.BOOLEAN) }) public class DefaultPurgeTask implements PurgeTask { private static final Logger LOG = LoggerFactory.getLogger(DefaultPurgeTask.class); diff --git a/plugins/sonar-findbugs-plugin/src/main/java/org/sonar/plugins/findbugs/FindbugsPlugin.java b/plugins/sonar-findbugs-plugin/src/main/java/org/sonar/plugins/findbugs/FindbugsPlugin.java index 115feb801d2..070dfbee8bd 100644 --- a/plugins/sonar-findbugs-plugin/src/main/java/org/sonar/plugins/findbugs/FindbugsPlugin.java +++ b/plugins/sonar-findbugs-plugin/src/main/java/org/sonar/plugins/findbugs/FindbugsPlugin.java @@ -20,6 +20,7 @@ package org.sonar.plugins.findbugs; import org.sonar.api.*; +import org.sonar.api.PropertyType; import java.util.ArrayList; import java.util.List; @@ -43,7 +44,7 @@ import java.util.List; project = true, module = true, global = true, - type = Property.Type.INTEGER), + type = PropertyType.INTEGER), @Property( key = FindbugsConstants.EXCLUDES_FILTERS_PROPERTY, name = "Excludes Filters", diff --git a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties index 7ff09ae2a5e..2f3e06c1be6 100644 --- a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -549,6 +549,12 @@ property.category.duplications=Duplications property.category.localization=Localization property.category.server_id=Server ID +property.error.notBoolean=Valid options are "true" and "false" +property.error.notInteger=Only digits are allowed +property.error.notFloat=Not a floating point number +property.error.notInOptions=Not a valid option + + #------------------------------------------------------------------------------ # diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java index 6e06dd8fde6..7932d233545 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java @@ -19,10 +19,8 @@ */ package org.sonar.plugins.squid; -import org.sonar.api.CoreProperties; -import org.sonar.api.Properties; -import org.sonar.api.Property; -import org.sonar.api.SonarPlugin; +import org.sonar.api.*; +import org.sonar.api.PropertyType; import org.sonar.plugins.squid.decorators.*; import java.util.Arrays; @@ -37,7 +35,7 @@ import java.util.List; project = true, global = true, category = CoreProperties.CATEGORY_JAVA, - type = Property.Type.BOOLEAN), + type = PropertyType.BOOLEAN), @Property(key = SquidPluginProperties.FIELDS_TO_EXCLUDE_FROM_LCOM4_COMPUTATION, defaultValue = SquidPluginProperties.FIELDS_TO_EXCLUDE_FROM_LCOM4_COMPUTATION_DEFAULT_VALUE, name = "List of fields to exclude from LCOM4 computation", @@ -55,7 +53,7 @@ import java.util.List; project = true, global = true, category = CoreProperties.CATEGORY_JAVA, - type = Property.Type.BOOLEAN) + type = PropertyType.BOOLEAN) }) public final class SquidPlugin extends SonarPlugin { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/Property.java b/sonar-plugin-api/src/main/java/org/sonar/api/Property.java index b48b0f5ec5a..c7820f15d3d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/Property.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/Property.java @@ -46,13 +46,6 @@ import java.lang.annotation.Target; public @interface Property { /** - * @since 2.15 - */ - public static enum Type { - STRING, TEXT, PASSWORD, BOOLEAN, INTEGER, FLOAT, SINGLE_SELECT_LIST - } - - /** * Unique key within all plugins. It's recommended to prefix the key by 'sonar.' and the plugin name. Examples : * 'sonar.cobertura.reportPath' and 'sonar.cpd.minimumTokens'. */ @@ -87,7 +80,7 @@ public @interface Property { /** * @since 2.15 */ - Type type() default Type.STRING; + PropertyType type() default PropertyType.STRING; /** * Options for *_LIST types diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/PropertyType.java b/sonar-plugin-api/src/main/java/org/sonar/api/PropertyType.java new file mode 100644 index 00000000000..356e4c1a65c --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/PropertyType.java @@ -0,0 +1,24 @@ +/* + * 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.api; + +public enum PropertyType { + STRING, TEXT, PASSWORD, BOOLEAN, INTEGER, FLOAT, SINGLE_SELECT_LIST +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/AesCipher.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/AesCipher.java index 1b5ee8511ef..4413b6353bf 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/config/AesCipher.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/AesCipher.java @@ -27,6 +27,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.sonar.api.CoreProperties; +import javax.annotation.Nullable; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -92,7 +93,7 @@ final class AesCipher extends Cipher { } @VisibleForTesting - Key loadSecretFileFromFile(String path) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException { + Key loadSecretFileFromFile(@Nullable String path) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException { if (StringUtils.isBlank(path)) { throw new IllegalStateException("Secret key not found. Please set the property " + CoreProperties.ENCRYPTION_SECRET_KEY_FILE); } 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 new file mode 100644 index 00000000000..ef98057d6b5 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java @@ -0,0 +1,158 @@ +/* + * 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.api.config; + +import com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.sonar.api.Property; +import org.sonar.api.PropertyType; + +import javax.annotation.Nullable; + +/** + * @since 2.15 + */ +public final class PropertyDefinition { + + public static final class Result { + private static final Result SUCCESS = new Result(null); + + private String errorKey = null; + + private static Result newError(String key) { + return new Result(key); + } + + private Result(String errorKey) { + this.errorKey = errorKey; + } + + public boolean isValid() { + return StringUtils.isBlank(errorKey); + } + + public @Nullable String getErrorKey() { + return errorKey; + } + } + + private String key; + private String defaultValue; + private String name; + private PropertyType type = PropertyType.STRING; + private String[] options; + private String description; + private String category; + private boolean onProject = false; + private boolean onModule = false; + private boolean isGlobal = true; + + private PropertyDefinition(Property annotation) { + this.key = annotation.key(); + this.name = annotation.name(); + this.defaultValue = annotation.defaultValue(); + this.description = annotation.description(); + this.isGlobal = annotation.global(); + this.onProject = annotation.project(); + this.onModule = annotation.module(); + this.category = annotation.category(); + this.type = annotation.type(); + this.options = annotation.options(); + } + + @VisibleForTesting + PropertyDefinition(PropertyType type, String[] options) { + this.type = type; + this.options = options; + } + + public static PropertyDefinition create(Property annotation) { + return new PropertyDefinition(annotation); + } + + public Result validate(@Nullable String value) { + // TODO REFACTORING REQUIRED HERE + Result result = Result.SUCCESS; + if (StringUtils.isNotBlank(value)) { + if (type == PropertyType.BOOLEAN) { + if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) { + result = Result.newError("notBoolean"); + } + } else if (type == PropertyType.INTEGER) { + if (!NumberUtils.isDigits(value)) { + result = Result.newError("notInteger"); + } + } else if (type == PropertyType.FLOAT) { + try { + Double.parseDouble(value); + } catch (NumberFormatException e) { + result = Result.newError("notFloat"); + } + } else if (type == PropertyType.SINGLE_SELECT_LIST) { + if (!ArrayUtils.contains(options, value)) { + result = Result.newError("notInOptions"); + } + } + } + return result; + } + + public String getKey() { + return key; + } + + public String getDefaultValue() { + return defaultValue; + } + + public String getName() { + return name; + } + + public PropertyType getType() { + return type; + } + + public String[] getOptions() { + return options; + } + + public String getDescription() { + return description; + } + + public String getCategory() { + return category; + } + + public boolean isOnProject() { + return onProject; + } + + public boolean isOnModule() { + return onModule; + } + + public boolean isGlobal() { + return isGlobal; + } +} 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 a090c1ecb88..13c9b374fa5 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 @@ -38,7 +38,7 @@ import java.util.Map; */ public final class PropertyDefinitions implements BatchComponent, ServerComponent { - private Map<String, Property> properties = Maps.newHashMap(); + private Map<String, PropertyDefinition> definitions = Maps.newHashMap(); private Map<String, String> categories = Maps.newHashMap(); public PropertyDefinitions(Object... components) { @@ -76,30 +76,31 @@ public final class PropertyDefinitions implements BatchComponent, ServerComponen return this; } - PropertyDefinitions addProperty(Property property) { - return addProperty(property, ""); + private PropertyDefinitions addProperty(Property property, String defaultCategory) { + PropertyDefinition definition = PropertyDefinition.create(property); + return add(definition, defaultCategory); } - PropertyDefinitions addProperty(Property property, String defaultCategory) { - if (!properties.containsKey(property.key())) { - properties.put(property.key(), property); - categories.put(property.key(), StringUtils.defaultIfBlank(property.category(), defaultCategory)); + private PropertyDefinitions add(PropertyDefinition definition, String defaultCategory) { + if (!definitions.containsKey(definition.getKey())) { + definitions.put(definition.getKey(), definition); + categories.put(definition.getKey(), StringUtils.defaultIfBlank(definition.getCategory(), defaultCategory)); } return this; } - public Property getProperty(String key) { - return properties.get(key); + public PropertyDefinition get(String key) { + return definitions.get(key); } - public Collection<Property> getProperties() { - return properties.values(); + public Collection<PropertyDefinition> getAll() { + return definitions.values(); } public String getDefaultValue(String key) { - Property prop = getProperty(key); - if (prop != null) { - return StringUtils.defaultIfEmpty(prop.defaultValue(), null); + PropertyDefinition def = get(key); + if (def != null) { + return StringUtils.defaultIfEmpty(def.getDefaultValue(), null); } return null; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/config/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/config/package-info.java new file mode 100644 index 00000000000..d3ae915cdb2 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/config/package-info.java @@ -0,0 +1,23 @@ +/* + * 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 + */ +@ParametersAreNonnullByDefault +package org.sonar.api.config; + +import javax.annotation.ParametersAreNonnullByDefault;
\ No newline at end of file diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/RulesCategory.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/RulesCategory.java index 3e5c1acdd5f..c860399da1f 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/RulesCategory.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/RulesCategory.java @@ -22,15 +22,8 @@ package org.sonar.api.rules; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Immutable; import org.sonar.api.database.BaseIdentifiable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Table; - /** * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007 */ diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionTest.java new file mode 100644 index 00000000000..7ccbda1d245 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionTest.java @@ -0,0 +1,153 @@ +/* + * 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.api.config; + +import org.hamcrest.core.Is; +import org.junit.Test; +import org.sonar.api.Properties; +import org.sonar.api.Property; +import org.sonar.api.PropertyType; +import org.sonar.api.utils.AnnotationUtils; + +import java.util.Arrays; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.hasItems; + +public class PropertyDefinitionTest { + + @Test + public void createFromAnnotation() { + Properties props = AnnotationUtils.getClassAnnotation(Init.class, Properties.class); + Property prop = props.value()[0]; + + PropertyDefinition def = PropertyDefinition.create(prop); + + assertThat(def.getKey(), Is.is("hello")); + assertThat(def.getName(), Is.is("Hello")); + assertThat(def.getDefaultValue(), Is.is("world")); + assertThat(def.getCategory(), Is.is("categ")); + assertThat(def.getOptions().length, Is.is(2)); + assertThat(Arrays.asList(def.getOptions()), hasItems("de", "en")); + assertThat(def.getDescription(), Is.is("desc")); + assertThat(def.getType(), Is.is(PropertyType.FLOAT)); + assertThat(def.isGlobal(), Is.is(false)); + assertThat(def.isOnProject(), Is.is(true)); + assertThat(def.isOnModule(), Is.is(true)); + } + + @Properties({ + @Property(key = "hello", name = "Hello", defaultValue = "world", description = "desc", + options = {"de", "en"}, category = "categ", type = PropertyType.FLOAT, global = false, project = true, module = true) + }) + static class Init { + } + + @Test + public void createFromAnnotation_default_values() { + Properties props = AnnotationUtils.getClassAnnotation(DefaultValues.class, Properties.class); + Property prop = props.value()[0]; + + PropertyDefinition def = PropertyDefinition.create(prop); + + assertThat(def.getKey(), Is.is("hello")); + assertThat(def.getName(), Is.is("Hello")); + assertThat(def.getDefaultValue(), Is.is("")); + assertThat(def.getCategory(), Is.is("")); + assertThat(def.getOptions().length, Is.is(0)); + assertThat(def.getDescription(), Is.is("")); + assertThat(def.getType(), Is.is(PropertyType.STRING)); + assertThat(def.isGlobal(), Is.is(true)); + assertThat(def.isOnProject(), Is.is(false)); + assertThat(def.isOnModule(), Is.is(false)); + } + + @Properties({ + @Property(key = "hello", name = "Hello") + }) + static class DefaultValues { + } + + @Test + public void validate_string() { + PropertyDefinition def = new PropertyDefinition(PropertyType.STRING, new String[0]); + + assertThat(def.validate(null).isValid(), is(true)); + assertThat(def.validate("").isValid(), is(true)); + assertThat(def.validate(" ").isValid(), is(true)); + assertThat(def.validate("foo").isValid(), is(true)); + } + + @Test + public void validate_boolean() { + PropertyDefinition def = new PropertyDefinition(PropertyType.BOOLEAN, new String[0]); + + assertThat(def.validate(null).isValid(), is(true)); + assertThat(def.validate("").isValid(), is(true)); + assertThat(def.validate(" ").isValid(), is(true)); + assertThat(def.validate("true").isValid(), is(true)); + assertThat(def.validate("false").isValid(), is(true)); + + assertThat(def.validate("foo").isValid(), is(false)); + assertThat(def.validate("foo").getErrorKey(), is("notBoolean")); + } + + @Test + public void validate_integer() { + PropertyDefinition def = new PropertyDefinition(PropertyType.INTEGER, new String[0]); + + assertThat(def.validate(null).isValid(), is(true)); + assertThat(def.validate("").isValid(), is(true)); + assertThat(def.validate(" ").isValid(), is(true)); + assertThat(def.validate("123456").isValid(), is(true)); + + assertThat(def.validate("foo").isValid(), is(false)); + assertThat(def.validate("foo").getErrorKey(), is("notInteger")); + } + + @Test + public void validate_float() { + PropertyDefinition def = new PropertyDefinition(PropertyType.FLOAT, new String[0]); + + assertThat(def.validate(null).isValid(), is(true)); + assertThat(def.validate("").isValid(), is(true)); + assertThat(def.validate(" ").isValid(), is(true)); + assertThat(def.validate("123456").isValid(), is(true)); + assertThat(def.validate("3.14").isValid(), is(true)); + + assertThat(def.validate("foo").isValid(), is(false)); + assertThat(def.validate("foo").getErrorKey(), is("notFloat")); + } + + @Test + public void validate_single_select_list() { + PropertyDefinition def = new PropertyDefinition(PropertyType.SINGLE_SELECT_LIST, new String[]{"de", "en"}); + + assertThat(def.validate(null).isValid(), is(true)); + assertThat(def.validate("").isValid(), is(true)); + assertThat(def.validate(" ").isValid(), is(true)); + assertThat(def.validate("de").isValid(), is(true)); + assertThat(def.validate("en").isValid(), is(true)); + + assertThat(def.validate("fr").isValid(), is(false)); + assertThat(def.validate("fr").getErrorKey(), is("notInOptions")); + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java index a5d8a0b2add..1320d9e376d 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/config/PropertyDefinitionsTest.java @@ -43,16 +43,16 @@ public class PropertyDefinitionsTest { assertProperties(def); } - private void assertProperties(PropertyDefinitions def) { - assertThat(def.getProperty("foo").name(), is("Foo")); - assertThat(def.getProperty("one").name(), is("One")); - assertThat(def.getProperty("two").name(), is("Two")); - assertThat(def.getProperty("unknown"), nullValue()); + private void assertProperties(PropertyDefinitions definitions) { + assertThat(definitions.get("foo").getName(), is("Foo")); + assertThat(definitions.get("one").getName(), is("One")); + assertThat(definitions.get("two").getName(), is("Two")); + assertThat(definitions.get("unknown"), nullValue()); - assertThat(def.getDefaultValue("foo"), nullValue()); - assertThat(def.getDefaultValue("two"), is("2")); + assertThat(definitions.getDefaultValue("foo"), nullValue()); + assertThat(definitions.getDefaultValue("two"), is("2")); - assertThat(def.getProperties().size(), is(3)); + assertThat(definitions.getAll().size(), is(3)); } @Property(key = "foo", name = "Foo") diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java index 4e88f6c939d..72a36ece437 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/config/SettingsTest.java @@ -23,34 +23,32 @@ import com.google.common.collect.ImmutableMap; import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Test; +import org.sonar.api.Properties; import org.sonar.api.Property; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class SettingsTest { private PropertyDefinitions definitions; + @Properties({ + @Property(key = "hello", name = "Hello", defaultValue = "world"), + @Property(key = "date", name = "Date", defaultValue = "2010-05-18"), + @Property(key = "boolean", name = "Boolean", defaultValue = "true"), + @Property(key = "falseboolean", name = "False Boolean", defaultValue = "false"), + @Property(key = "integer", name = "Integer", defaultValue = "12345"), + @Property(key = "array", name = "Array", defaultValue = "one,two,three") + }) + static class Init { + } + @Before public void initDefinitions() { definitions = new PropertyDefinitions(); - definitions.addProperty(newProperty("hello", "world")); - definitions.addProperty(newProperty("date", "2010-05-18")); - definitions.addProperty(newProperty("boolean", "true")); - definitions.addProperty(newProperty("falseboolean", "false")); - definitions.addProperty(newProperty("integer", "12345")); - definitions.addProperty(newProperty("array", "one,two,three")); - } - - private Property newProperty(String key, String defaultValue) { - Property prop = mock(Property.class); - when(prop.key()).thenReturn(key); - when(prop.defaultValue()).thenReturn(defaultValue); - return prop; + definitions.addComponent(Init.class); } @Test diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java index bfb16d5f7af..db6f03b1106 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java @@ -102,8 +102,8 @@ public class ComponentContainerTest { container.addSingleton(ComponentWithProperty.class); PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); - assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); - assertThat(propertyDefinitions.getProperty("foo").defaultValue(), is("bar")); + assertThat(propertyDefinitions.get("foo"), notNullValue()); + assertThat(propertyDefinitions.get("foo").getDefaultValue(), is("bar")); } @Test @@ -113,7 +113,7 @@ public class ComponentContainerTest { container.declareExtension(plugin, ComponentWithProperty.class); PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); - assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); + assertThat(propertyDefinitions.get("foo"), notNullValue()); assertThat(container.getComponentByType(ComponentWithProperty.class), nullValue()); } @@ -124,7 +124,7 @@ public class ComponentContainerTest { container.addExtension(plugin, ComponentWithProperty.class); PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); - assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); + assertThat(propertyDefinitions.get("foo"), notNullValue()); assertThat(container.getComponentByType(ComponentWithProperty.class), notNullValue()); } diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java b/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java index 27d8df7e0a3..191c0e88cbd 100644 --- a/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java +++ b/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java @@ -23,6 +23,7 @@ import org.apache.commons.io.IOUtils; import org.slf4j.LoggerFactory; import org.sonar.api.Properties; import org.sonar.api.Property; +import org.sonar.api.PropertyType; import org.sonar.api.ServerComponent; import org.sonar.api.config.Settings; import org.sonar.api.utils.HttpDownloader; @@ -49,7 +50,7 @@ import java.util.Date; project = false, global = false, // hidden from UI category = "Update Center", - type = Property.Type.BOOLEAN), + type = PropertyType.BOOLEAN), @Property( key = UpdateCenterClient.URL_PROPERTY, defaultValue = "http://update.sonarsource.org/update-center.properties", diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb index c486dfd7d27..88ebe73790d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb @@ -126,13 +126,13 @@ class ProjectController < ApplicationController end @category=params[:category] ||= 'general' - @properties_per_category={} + @definitions_per_category={} definitions = java_facade.getPropertyDefinitions() - properties = definitions.getProperties().select { |property| (@project.module? && property.module()) || (@project.project? && property.project()) } + properties = definitions.getAll().select { |property| (@project.module? && property.isOnModule()) || (@project.project? && property.isOnProject()) } properties.each do |property| - category = definitions.getCategory(property.key()) - @properties_per_category[category]||=[] - @properties_per_category[category]<<property + category = definitions.getCategory(property.getKey()) + @definitions_per_category[category]||=[] + @definitions_per_category[category]<<property end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/settings_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/settings_controller.rb index 653c42d81ab..18c7e8f0797 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/settings_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/settings_controller.rb @@ -20,7 +20,7 @@ class SettingsController < ApplicationController SECTION=Navigation::SECTION_CONFIGURATION - + SPECIAL_CATEGORIES=['email', 'encryption', 'server_id'] verify :method => :post, :only => ['update'], :redirect_to => {:action => :index} @@ -32,39 +32,39 @@ class SettingsController < ApplicationController end def update - project=nil + @project=nil if params[:resource_id] - project=Project.by_key(params[:resource_id]) - access_denied unless (project && is_admin?(project)) + @project=Project.by_key(params[:resource_id]) + access_denied unless (@project && is_admin?(@project)) else access_denied unless is_admin? end - load_properties(project) + load_properties(@project) + + @persisted_properties_per_key={} + if @category && @definitions_per_category[@category] + @definitions_per_category[@category].each do |property| + value=params[property.getKey()] - if @category && @properties_per_category[@category] - @properties_per_category[@category].each do |property| - value=params[property.key()] - persisted_property = Property.find(:first, :conditions => {:prop_key=> property.key(), :resource_id => (project ? project.id : nil), :user_id => nil}) + persisted_property = Property.find(:first, :conditions => {:prop_key=> property.key(), :resource_id => (@project ? @project.id : nil), :user_id => nil}) if persisted_property if value.empty? - Property.delete_all('prop_key' => property.key(), 'resource_id' => (project ? project.id : nil), 'user_id' => nil) + Property.delete_all('prop_key' => property.key(), 'resource_id' => (@project ? @project.id : nil), 'user_id' => nil) elsif persisted_property.text_value != value.to_s persisted_property.text_value = value.to_s - persisted_property.save! + persisted_property.save + @persisted_properties_per_key[persisted_property.key]=persisted_property end elsif !value.blank? - Property.create(:prop_key => property.key(), :text_value => value.to_s, :resource_id => (project ? project.id : nil)) + persisted_property=Property.create(:prop_key => property.key(), :text_value => value.to_s, :resource_id => (@project ? @project.id : nil)) + @persisted_properties_per_key[persisted_property.key]=persisted_property end end java_facade.reloadConfiguration() - flash[:notice] = 'Parameters updated' - end - if project - redirect_to :controller => 'project', :action => 'settings', :id => project.id, :category => @category - else - redirect_to :controller => 'settings', :action => 'index', :category => @category + params[:layout]='false' + render :partial => 'settings/properties' end end @@ -72,18 +72,18 @@ class SettingsController < ApplicationController def load_properties(project) @category=params[:category] - @properties_per_category={} + @definitions_per_category={} definitions = java_facade.getPropertyDefinitions() - definitions.getProperties().select {|property| - (project.nil? && property.global) || (project && project.module? && property.module()) || (project && project.project? && property.project()) - }.each do |property| - category = definitions.getCategory(property.key()) - @properties_per_category[category]||=[] - @properties_per_category[category]<<property + definitions.getAll().select { |property_definition| + (project.nil? && property_definition.isGlobal()) || (project && project.module? && property_definition.isOnModule()) || (project && project.project? && property_definition.isOnProject()) + }.each do |property_definition| + category = definitions.getCategory(property_definition.getKey()) + @definitions_per_category[category]||=[] + @definitions_per_category[category]<<property_definition end SPECIAL_CATEGORIES.each do |category| - @properties_per_category[category]=[] + @definitions_per_category[category]=[] end end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb index ccef420c136..b388a5bec6b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 # class Property < ActiveRecord::Base + validates_presence_of :prop_key def key prop_key @@ -87,8 +88,22 @@ class Property < ActiveRecord::Base xml end + def java_definition + @java_definition ||= + begin + Java::OrgSonarServerUi::JRubyFacade.getInstance().getPropertyDefinitions().get(key) + end + end + private + def validate + if java_definition + validation_result=java_definition.validate(text_value) + errors.add_to_base(validation_result.getErrorKey()) unless validation_result.isValid() + end + end + def self.reload_java_configuration Java::OrgSonarServerUi::JRubyFacade.getInstance().reloadConfiguration() end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/project/settings.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/project/settings.html.erb index cb5e508f23b..8e2f68f1870 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/project/settings.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/project/settings.html.erb @@ -3,7 +3,7 @@ <h1 class="marginbottom10">Settings</h1> <div class="yui-g widget" id="widget_plugins"> - <%= render :partial => 'settings/plugins', :locals => {:project=>@project} %> + <%= render :partial => 'settings/settings', :locals => {:project=>@project} %> </div> </div>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_plugins.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_plugins.html.erb deleted file mode 100644 index 87a5a99b803..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_plugins.html.erb +++ /dev/null @@ -1,128 +0,0 @@ -<style type="text/css"> - #plugins .plugin { - padding: 5px; - border: 1px solid #ddd; - background-color: #fff; - } - - #plugins .plugin h2 { - margin-left: 10px; - font-size: 122%; - color: #333; - } - - #plugins .plugin h3 { - margin-left: 5px; - } - - #plugins .plugin p { - padding: 5px 5px; - } - - #plugins .plugin img { - padding: 5px 0 0 5px; - } -</style> -<script type="text/javascript"> - function enlargeTextInput(propertyKey) { - var eltId = 'input_' + propertyKey; - var textValue = $F(eltId); - var textArea = '<textarea class="width100" id="' + propertyKey + '" name="' + propertyKey + '" rows="10" id="input_' + propertyKey + '">' + textValue + '</textarea>'; - $(eltId).parentNode.replace(textArea); - } -</script> -<div id="plugins"> - <table width="100%"> - <tr> - <td width="1%" nowrap class="column first"> - <table class="data selector"> - <thead> - <tr> - <th> - <span>Category</span> - </th> - </tr> - </thead> - <tbody> - <% - @properties_per_category.keys.sort_by { |category| message("property.category.#{category}", :default => category).upcase }.each do |category| - if !@properties_per_category[category].empty? || SettingsController::SPECIAL_CATEGORIES.include?(category) - %> - <tr class="select <%= cycle('even', 'odd', :name => 'category') -%> <%= 'selected' if @category==category -%>" id="select_<%= category -%>"> - <td><%= link_to message("property.category.#{category}", :default => category), :overwrite_params => {:category => category} -%></td> - </tr> - <% end - end - %> - </tbody> - </table> - <br/> - </td> - - <td class="column"> - <% if @category && @properties_per_category[@category] - category_name = message("property.category.#{@category}", :default => @category) - if SettingsController::SPECIAL_CATEGORIES.include?(@category) - %> - <%= render :partial => 'special', :locals => {:url => url_for(:controller => "#{@category}_configuration")} -%> - <% - elsif !@properties_per_category[@category].empty? - %> - <% form_tag :controller => :settings, :action => :update do %> - <%= hidden_field_tag('category', @category) -%> - <% if @project %> - <input type="hidden" name="resource_id" value="<%= @project.id -%>"/> - <% end %> - <table class="data marginbottom10"> - <thead> - <tr> - <th> - <span><%= h(category_name) -%></span> - </th> - </tr> - </thead> - <tbody> - <% - if @properties_per_category[@category] - @properties_per_category[@category].each do |property| - value = Property.value(property.key(), (@project ? @project.id : nil), '') - - # for backward-compatibility with properties that do not define the type TEXT - property_type = value.include?("\n") ? 'TEXT' : property.type - %> - <tr class="<%= cycle('even', 'odd', :name => 'properties') -%>"> - <td style="padding: 10px"> - <h3> - <%= message("property.#{property.key()}.name", :default => property.name()) -%> - <br/><span class="note"><%= property.key() -%></span> - </h3> - <% - desc=message("property.#{property.key()}.description", :default => property.description()) - if desc.present? %> - <p class="marginbottom10"><%= desc -%></p> - <% end %> - <div><%= render :partial => "settings/type_#{property_type}", :locals => {:property => property, :value => value} -%></div> - <p> - <% - default_prop_value = (@project ? Property.value(property.key(), nil, property.defaultValue()) : property.defaultValue()) - unless default_prop_value.blank? %> - <span class="note">Default : <%= h default_prop_value -%></span> - <% end %> - </p> - </td> - </tr> - <% end - end - %> - </tbody> - </table> - <% save_message=message('settings.save_category', :params => [category_name]) %> - <%= submit_tag(save_message, :disable_with => save_message, :id => 'save') -%> - <% end %> - <% end - end - %> - </td> - </tr> - </table> -</div> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_properties.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_properties.html.erb new file mode 100644 index 00000000000..fc2fbd2ae09 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_properties.html.erb @@ -0,0 +1,85 @@ +<% if @category && @definitions_per_category[@category] + category_name = message("property.category.#{@category}", :default => @category) + if SettingsController::SPECIAL_CATEGORIES.include?(@category) +%> + <%= render :partial => 'special', :locals => {:url => url_for(:controller => "#{@category}_configuration")} -%> + <% + elsif !@definitions_per_category[@category].empty? + %> + <% form_remote_tag :url => {:controller => 'settings', :action => 'update', :category => @category, :resource_id => @project ? @project.id : nil}, + :method => :post, + :before => "$('submit_settings').hide();$('loading_settings').show()", + :update => 'properties' do -%> + + <table class="data marginbottom10"> + <thead> + <tr> + <th> + <span><%= h(category_name) -%></span> + </th> + </tr> + </thead> + <tbody> + <% + if @definitions_per_category[@category] + @definitions_per_category[@category].each do |property| + value = nil + + # set when form has been submitted but some errors have been raised + if @persisted_properties_per_key + p = @persisted_properties_per_key[property.key] + if p + value = p.text_value + end + end + + + # if fresh form or no error, get the current value + value = Property.value(property.getKey(), (@project ? @project.id : nil), '') unless value + + # for backward-compatibility with properties that do not define the type TEXT + property_type = value.include?("\n") ? 'TEXT' : property.getType() + %> + <tr class="<%= cycle('even', 'odd', :name => 'properties') -%>"> + <td style="padding: 10px" id="foo_<%= property.getKey() -%>"> + <h3> + <%= message("property.#{property.key()}.name", :default => property.name()) -%> + <br/><span class="note"><%= property.getKey() -%></span> + </h3> + <% + desc=message("property.#{property.key()}.description", :default => property.description()) + if desc.present? %> + <p class="marginbottom10"><%= desc -%></p> + <% end %> + <div><%= render :partial => "settings/type_#{property_type}", :locals => {:property => property, :value => value} -%></div> + <% + if p + p.errors.each_full do |error| + %> + <div class="error"><%= message("property.error.#{error}") -%></div> + <% + end + end + %> + <p> + <% + default_prop_value = (@project ? Property.value(property.key(), nil, property.defaultValue()) : property.defaultValue()) + unless default_prop_value.blank? %> + <span class="note">Default : <%= h default_prop_value -%></span> + <% end %> + </p> + </td> + </tr> + <% end + end + %> + </tbody> + </table> + <div> + <%= submit_tag(message('settings.save_category', :params => [category_name]), :id => 'submit_settings') -%> + <img src="<%= ApplicationController.root_context -%>/images/loading.gif" id="loading_settings" style="display:none"> + </div> + <% end %> + <% end + end + %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_settings.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_settings.html.erb new file mode 100644 index 00000000000..cbd85572a12 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_settings.html.erb @@ -0,0 +1,69 @@ +<style type="text/css"> + #plugins .plugin { + padding: 5px; + border: 1px solid #ddd; + background-color: #fff; + } + + #plugins .plugin h2 { + margin-left: 10px; + font-size: 122%; + color: #333; + } + + #plugins .plugin h3 { + margin-left: 5px; + } + + #plugins .plugin p { + padding: 5px 5px; + } + + #plugins .plugin img { + padding: 5px 0 0 5px; + } +</style> +<script type="text/javascript"> + function enlargeTextInput(propertyKey) { + var eltId = 'input_' + propertyKey; + var textValue = $F(eltId); + var textArea = '<textarea class="width100" id="' + propertyKey + '" name="' + propertyKey + '" rows="10" id="input_' + propertyKey + '">' + textValue + '</textarea>'; + $(eltId).parentNode.replace(textArea); + } +</script> +<div id="plugins"> + <table width="100%"> + <tr> + <td width="1%" nowrap class="column first"> + <table class="data selector"> + <thead> + <tr> + <th> + <span>Category</span> + </th> + </tr> + </thead> + <tbody> + <% + @definitions_per_category.keys.sort_by { |category| message("property.category.#{category}", :default => category).upcase }.each do |category| + if !@definitions_per_category[category].empty? || SettingsController::SPECIAL_CATEGORIES.include?(category) + %> + <tr class="select <%= cycle('even', 'odd', :name => 'category') -%> <%= 'selected' if @category==category -%>" id="select_<%= category -%>"> + <td><%= link_to message("property.category.#{category}", :default => category), :overwrite_params => {:category => category} -%></td> + </tr> + <% end + end + %> + </tbody> + </table> + <br/> + </td> + + <td class="column"> + <div id="properties"> + <%= render :partial => 'settings/properties' -%> + </div> + </td> + </tr> + </table> +</div> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_sidebar.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_sidebar.html.erb new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_sidebar.html.erb diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_type_SINGLE_SELECT_LIST.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_type_SINGLE_SELECT_LIST.html.erb index a6f905a3038..a317e48ef38 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_type_SINGLE_SELECT_LIST.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/_type_SINGLE_SELECT_LIST.html.erb @@ -1,6 +1,6 @@ <select name="<%= h property.key -%>" id="input_<%= h property.key-%>"> <option value=""><%= message('default') -%></option> <% property.options.each do |option| %> - <option value="<%= h option -%>"><%= h option -%></option> + <option value="<%= h option -%>" <%= 'selected' if value && value==option -%>><%= h option -%></option> <% end %> </select>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/index.html.erb index d0fc6625477..81fa7362a09 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/settings/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/settings/index.html.erb @@ -1 +1 @@ -<%= render :partial => 'plugins', :locals => {:project=>nil} %>
\ No newline at end of file +<%= render :partial => 'settings', :locals => {:project=>nil} %>
\ No newline at end of file |