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 */
020package org.sonar.api.config;
021
022import com.google.common.collect.ImmutableList;
023import org.apache.commons.lang.ArrayUtils;
024import org.apache.commons.lang.StringUtils;
025import org.apache.commons.lang.math.NumberUtils;
026import org.sonar.api.Property;
027import org.sonar.api.PropertyType;
028
029import javax.annotation.Nullable;
030
031import java.util.List;
032
033/**
034 * @since 3.0
035 */
036public final class PropertyDefinition {
037
038  public static final class Result {
039    private static final Result SUCCESS = new Result(null);
040
041    private String errorKey = null;
042
043    private static Result newError(String key) {
044      return new Result(key);
045    }
046
047    @Nullable
048    private Result(@Nullable String errorKey) {
049      this.errorKey = errorKey;
050    }
051
052    public boolean isValid() {
053      return StringUtils.isBlank(errorKey);
054    }
055
056    @Nullable
057    public String getErrorKey() {
058      return errorKey;
059    }
060  }
061
062  private final String key;
063  private final String defaultValue;
064  private final String name;
065  private final PropertyType type;
066  private final String[] options;
067  private final String description;
068  private final String category;
069  private final boolean onProject;
070  private final boolean onModule;
071  private final boolean isGlobal;
072  private final boolean multiValues;
073  private final String propertySetKey;
074  private final String deprecatedKey;
075  private final List<PropertyFieldDefinition> fields;
076
077  private PropertyDefinition(Property annotation) {
078    this.key = annotation.key();
079    this.name = annotation.name();
080    this.defaultValue = annotation.defaultValue();
081    this.description = annotation.description();
082    this.isGlobal = annotation.global();
083    this.onProject = annotation.project();
084    this.onModule = annotation.module();
085    this.category = annotation.category();
086    this.type = fixType(annotation.key(), annotation.type());
087    this.options = annotation.options();
088    this.multiValues = annotation.multiValues();
089    this.propertySetKey = annotation.propertySetKey();
090    this.fields = ImmutableList.copyOf(PropertyFieldDefinition.create(annotation.fields()));
091    this.deprecatedKey = annotation.deprecatedKey();
092  }
093
094  private PropertyDefinition(String key, PropertyType type, String[] options) {
095    this.key = key;
096    this.name = null;
097    this.defaultValue = null;
098    this.description = null;
099    this.isGlobal = true;
100    this.onProject = false;
101    this.onModule = false;
102    this.category = null;
103    this.type = type;
104    this.options = options;
105    this.multiValues = false;
106    this.propertySetKey = null;
107    this.fields = null;
108    this.deprecatedKey = null;
109  }
110
111  private static PropertyType fixType(String key, PropertyType type) {
112    // Auto-detect passwords and licenses for old versions of plugins that
113    // do not declare property types
114    if (type == PropertyType.STRING) {
115      if (StringUtils.endsWith(key, ".password.secured")) {
116        return PropertyType.PASSWORD;
117      } else if (StringUtils.endsWith(key, ".license.secured")) {
118        return PropertyType.LICENSE;
119      }
120    }
121    return type;
122  }
123
124  public static PropertyDefinition create(Property annotation) {
125    return new PropertyDefinition(annotation);
126  }
127
128  public static PropertyDefinition create(String key, PropertyType type, String[] options) {
129    return new PropertyDefinition(key, type, options);
130  }
131
132  public Result validate(@Nullable String value) {
133    return validate(type, value, options);
134  }
135
136  static Result validate(PropertyType type, @Nullable String value, String[] options) {
137    if (StringUtils.isNotBlank(value)) {
138      if (type == PropertyType.BOOLEAN) {
139        if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) {
140          return Result.newError("notBoolean");
141        }
142      } else if (type == PropertyType.INTEGER) {
143        if (!NumberUtils.isDigits(value)) {
144          return Result.newError("notInteger");
145        }
146      } else if (type == PropertyType.FLOAT) {
147        try {
148          Double.parseDouble(value);
149        } catch (NumberFormatException e) {
150          return Result.newError("notFloat");
151        }
152      } else if (type == PropertyType.SINGLE_SELECT_LIST) {
153        if (!ArrayUtils.contains(options, value)) {
154          return Result.newError("notInOptions");
155        }
156      }
157    }
158    return Result.SUCCESS;
159  }
160
161  public String getKey() {
162    return key;
163  }
164
165  public String getDefaultValue() {
166    return defaultValue;
167  }
168
169  public String getName() {
170    return name;
171  }
172
173  public PropertyType getType() {
174    return type;
175  }
176
177  public String[] getOptions() {
178    return options.clone();
179  }
180
181  public String getDescription() {
182    return description;
183  }
184
185  public String getCategory() {
186    return category;
187  }
188
189  public boolean isOnProject() {
190    return onProject;
191  }
192
193  public boolean isOnModule() {
194    return onModule;
195  }
196
197  public boolean isGlobal() {
198    return isGlobal;
199  }
200
201  /**
202   * @since 3.3
203   */
204  public boolean isMultiValues() {
205    return multiValues;
206  }
207
208  /**
209   * @since 3.3
210   */
211  public String getPropertySetKey() {
212    return propertySetKey;
213  }
214
215  /**
216   * @since 3.3
217   */
218  public List<PropertyFieldDefinition> getFields() {
219    return fields;
220  }
221
222  /**
223   * @since 3.4
224   */
225  public String getDeprecatedKey() {
226    return deprecatedKey;
227  }
228}