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