001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.api.config;
021    
022    import org.apache.commons.lang.ArrayUtils;
023    import org.apache.commons.lang.StringUtils;
024    import org.apache.commons.lang.math.NumberUtils;
025    import org.sonar.api.Property;
026    import org.sonar.api.PropertyType;
027    
028    import javax.annotation.Nullable;
029    
030    /**
031     * @since 3.0
032     */
033    public final class PropertyDefinition {
034    
035      public static final class Result {
036        private static final Result SUCCESS = new Result(null);
037    
038        private String errorKey = null;
039    
040        private static Result newError(String key) {
041          return new Result(key);
042        }
043    
044        @Nullable
045        private Result(@Nullable String errorKey) {
046          this.errorKey = errorKey;
047        }
048    
049        public boolean isValid() {
050          return StringUtils.isBlank(errorKey);
051        }
052    
053        @Nullable
054        public String getErrorKey() {
055          return errorKey;
056        }
057      }
058    
059      private String key;
060      private String defaultValue;
061      private String name;
062      private PropertyType type = PropertyType.STRING;
063      private String[] options;
064      private String description;
065      private String category;
066      private boolean onProject = false;
067      private boolean onModule = false;
068      private boolean isGlobal = true;
069    
070      private PropertyDefinition(Property annotation) {
071        this.key = annotation.key();
072        this.name = annotation.name();
073        this.defaultValue = annotation.defaultValue();
074        this.description = annotation.description();
075        this.isGlobal = annotation.global();
076        this.onProject = annotation.project();
077        this.onModule = annotation.module();
078        this.category = annotation.category();
079        this.type = fixType(annotation.key(), annotation.type());
080        this.options = annotation.options();
081      }
082    
083      private PropertyType fixType(String key, PropertyType type) {
084        // Auto-detect passwords and licenses for old versions of plugins that
085        // do not declare property types
086        PropertyType fix = type;
087        if (type == PropertyType.STRING) {
088          if (StringUtils.endsWith(key, ".password.secured")) {
089            fix = PropertyType.PASSWORD;
090          } else if (StringUtils.endsWith(key, ".license.secured")) {
091            fix = PropertyType.LICENSE;
092          }
093        }
094        return fix;
095      }
096    
097      private PropertyDefinition(String key, PropertyType type, String[] options) {
098        this.key = key;
099        this.type = type;
100        this.options = options;
101      }
102    
103      public static PropertyDefinition create(Property annotation) {
104        return new PropertyDefinition(annotation);
105      }
106    
107      public static PropertyDefinition create(String key, PropertyType type, String[] options) {
108        return new PropertyDefinition(key, type, options);
109      }
110    
111      public Result validate(@Nullable String value) {
112        // TODO REFACTORING REQUIRED HERE
113        Result result = Result.SUCCESS;
114        if (StringUtils.isNotBlank(value)) {
115          if (type == PropertyType.BOOLEAN) {
116            if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) {
117              result = Result.newError("notBoolean");
118            }
119          } else if (type == PropertyType.INTEGER) {
120            if (!NumberUtils.isDigits(value)) {
121              result = Result.newError("notInteger");
122            }
123          } else if (type == PropertyType.FLOAT) {
124            try {
125              Double.parseDouble(value);
126            } catch (NumberFormatException e) {
127              result = Result.newError("notFloat");
128            }
129          } else if (type == PropertyType.SINGLE_SELECT_LIST) {
130            if (!ArrayUtils.contains(options, value)) {
131              result = Result.newError("notInOptions");
132            }
133          }
134        }
135        return result;
136      }
137    
138      public String getKey() {
139        return key;
140      }
141    
142      public String getDefaultValue() {
143        return defaultValue;
144      }
145    
146      public String getName() {
147        return name;
148      }
149    
150      public PropertyType getType() {
151        return type;
152      }
153    
154      public String[] getOptions() {
155        return options.clone();
156      }
157    
158      public String getDescription() {
159        return description;
160      }
161    
162      public String getCategory() {
163        return category;
164      }
165    
166      public boolean isOnProject() {
167        return onProject;
168      }
169    
170      public boolean isOnModule() {
171        return onModule;
172      }
173    
174      public boolean isGlobal() {
175        return isGlobal;
176      }
177    }