001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube 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 * SonarQube 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 License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.api.server.rule;
021
022 import org.apache.commons.lang.StringEscapeUtils;
023 import org.apache.commons.lang.StringUtils;
024 import org.sonar.api.PropertyType;
025
026 import java.util.List;
027
028 import static com.google.common.collect.Lists.newArrayList;
029
030 /**
031 * @since 4.2
032 */
033 public final class RuleParamType {
034
035 private static final String OPTION_SEPARATOR = ",";
036
037 public static final RuleParamType STRING = new RuleParamType("STRING");
038 public static final RuleParamType TEXT = new RuleParamType("TEXT");
039 public static final RuleParamType BOOLEAN = new RuleParamType("BOOLEAN");
040 public static final RuleParamType INTEGER = new RuleParamType("INTEGER");
041 public static final RuleParamType FLOAT = new RuleParamType("FLOAT");
042
043 private static final String CSV_SPLIT_REGEX = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
044 private static final String VALUES_PARAM = "values";
045 private static final String MULTIPLE_PARAM = "multiple";
046 private static final String PARAMETER_SEPARATOR = "=";
047
048 private final String type;
049 private final List<String> values;
050 private final boolean multiple;
051
052 // format is "type|comma-separated list of options", for example "INTEGER" or "SINGLE_SELECT_LIST|foo=one,bar,baz=two"
053 private final String key;
054
055 private RuleParamType(String type, String... options) {
056 this(type, false, options);
057 }
058
059 private RuleParamType(String type, boolean multiple, String... values) {
060 this.type = type;
061 this.values = newArrayList(values);
062 StringBuilder sb = new StringBuilder();
063 sb.append(type);
064 if (multiple) {
065 sb.append(OPTION_SEPARATOR);
066 sb.append(MULTIPLE_PARAM + PARAMETER_SEPARATOR);
067 sb.append(Boolean.toString(multiple));
068 }
069 if (values.length > 0) {
070 sb.append(OPTION_SEPARATOR);
071 sb.append(VALUES_PARAM + PARAMETER_SEPARATOR);
072 sb.append(StringEscapeUtils.escapeCsv(valuesToCsv(values)));
073 }
074 this.key = sb.toString();
075 this.multiple = multiple;
076 }
077
078 private String valuesToCsv(String... values) {
079 StringBuilder sb = new StringBuilder();
080 for (String value : values) {
081 sb.append(StringEscapeUtils.escapeCsv(value));
082 sb.append(OPTION_SEPARATOR);
083 }
084 return sb.toString();
085 }
086
087 public String type() {
088 return type;
089 }
090
091 public List<String> values() {
092 return values;
093 }
094
095 public boolean multiple() {
096 return multiple;
097 }
098
099 public static RuleParamType singleListOfValues(String... acceptedValues) {
100 // reuse the same type as plugin properties in order to
101 // benefit from shared helpers (validation, HTML component)
102 String type = PropertyType.SINGLE_SELECT_LIST.name();
103 return new RuleParamType(type, acceptedValues);
104 }
105
106 public static RuleParamType multipleListOfValues(String... acceptedValues) {
107 // reuse the same type as plugin properties in order to
108 // benefit from shared helpers (validation, HTML component)
109 String type = PropertyType.SINGLE_SELECT_LIST.name();
110 return new RuleParamType(type, true, acceptedValues);
111 }
112
113 // TODO validate format
114 public static RuleParamType parse(String s) {
115 // deprecated formats
116 if ("i".equals(s) || "i{}".equals(s)) {
117 return INTEGER;
118 }
119 if ("s".equals(s) || "s{}".equals(s) || "r".equals(s) || "REGULAR_EXPRESSION".equals(s)) {
120 return STRING;
121 }
122 if ("b".equals(s)) {
123 return BOOLEAN;
124 }
125 if (s.startsWith("s[")) {
126 String values = StringUtils.substringBetween(s, "[", "]");
127 return multipleListOfValues(StringUtils.split(values, ','));
128 }
129
130 // standard format
131 String format = StringUtils.substringBefore(s, OPTION_SEPARATOR);
132 String values = null;
133 boolean multiple = false;
134 String[] options = s.split(CSV_SPLIT_REGEX);
135 for (String option : options) {
136 String opt = StringEscapeUtils.unescapeCsv(option);
137 if (opt.startsWith(VALUES_PARAM + PARAMETER_SEPARATOR)) {
138 values = StringEscapeUtils.unescapeCsv(StringUtils.substringAfter(opt, VALUES_PARAM + PARAMETER_SEPARATOR));
139 } else if (opt.startsWith(MULTIPLE_PARAM + PARAMETER_SEPARATOR)) {
140 multiple = Boolean.parseBoolean(StringUtils.substringAfter(opt, MULTIPLE_PARAM + PARAMETER_SEPARATOR));
141 }
142 }
143 if (values == null || StringUtils.isBlank(values)) {
144 return new RuleParamType(format);
145 }
146 return new RuleParamType(format, multiple, values.split(CSV_SPLIT_REGEX));
147 }
148
149 @Override
150 public boolean equals(Object o) {
151 if (this == o) {
152 return true;
153 }
154 if (o == null || getClass() != o.getClass()) {
155 return false;
156 }
157
158 RuleParamType that = (RuleParamType) o;
159 return key.equals(that.key);
160 }
161
162 @Override
163 public int hashCode() {
164 return key.hashCode();
165 }
166
167 @Override
168 public String toString() {
169 return key;
170 }
171 }