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 }