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 com.google.common.collect.Lists; 023 import com.google.common.collect.Maps; 024 import org.apache.commons.lang.ArrayUtils; 025 import org.apache.commons.lang.StringUtils; 026 import org.sonar.api.BatchComponent; 027 import org.sonar.api.ServerComponent; 028 import org.sonar.api.utils.DateUtils; 029 030 import javax.annotation.Nullable; 031 import java.util.*; 032 033 /** 034 * Project Settings on batch side, Global Settings on server side. This component does not access to database, so 035 * property changed via setter methods are not persisted. 036 * 037 * <p> 038 * This component replaces the deprecated org.apache.commons.configuration.Configuration 039 * </p> 040 * 041 * @since 2.12 042 */ 043 public class Settings implements BatchComponent, ServerComponent { 044 045 protected final Map<String, String> properties; 046 protected final PropertyDefinitions definitions; 047 private final Encryption encryption; 048 049 public Settings() { 050 this(new PropertyDefinitions()); 051 } 052 053 public Settings(PropertyDefinitions definitions) { 054 this.properties = Maps.newHashMap(); 055 this.definitions = definitions; 056 this.encryption = new Encryption(this); 057 } 058 059 public final Encryption getEncryption() { 060 return encryption; 061 } 062 063 public final String getDefaultValue(String key) { 064 return definitions.getDefaultValue(key); 065 } 066 067 public final boolean hasKey(String key) { 068 return properties.containsKey(key); 069 } 070 071 public final boolean hasDefaultValue(String key) { 072 return StringUtils.isNotEmpty(getDefaultValue(key)); 073 } 074 075 public final String getString(String key) { 076 String value = properties.get(key); 077 if (value == null) { 078 value = getDefaultValue(key); 079 } else if (encryption.isEncrypted(value)) { 080 try { 081 value = encryption.decrypt(value); 082 } catch (Exception e) { 083 throw new IllegalStateException("Fail to decrypt the property " + key + ". Please check your secret key."); 084 } 085 } 086 return value; 087 } 088 089 /** 090 * Does not decrypt value. 091 */ 092 protected String getClearString(String key) { 093 String value = properties.get(key); 094 if (value == null) { 095 value = getDefaultValue(key); 096 } 097 return value; 098 } 099 100 public final boolean getBoolean(String key) { 101 String value = getString(key); 102 return StringUtils.isNotEmpty(value) && Boolean.parseBoolean(value); 103 } 104 105 public final int getInt(String key) { 106 String value = getString(key); 107 if (StringUtils.isNotEmpty(value)) { 108 return Integer.parseInt(value); 109 } 110 return 0; 111 } 112 113 public final long getLong(String key) { 114 String value = getString(key); 115 if (StringUtils.isNotEmpty(value)) { 116 return Long.parseLong(value); 117 } 118 return 0L; 119 } 120 121 public final Date getDate(String key) { 122 String value = getString(key); 123 if (StringUtils.isNotEmpty(value)) { 124 return DateUtils.parseDate(value); 125 } 126 return null; 127 } 128 129 public final Date getDateTime(String key) { 130 String value = getString(key); 131 if (StringUtils.isNotEmpty(value)) { 132 return DateUtils.parseDateTime(value); 133 } 134 return null; 135 } 136 137 /** 138 * Value is splitted by comma and trimmed. 139 * <p/> 140 * Examples : 141 * <ul> 142 * <li>"one,two,three " -> ["one", "two", "three"]</li> 143 * <li>" one, two, three " -> ["one", "two", "three"]</li> 144 * <li>"one, , three" -> ["one", "", "three"]</li> 145 * </ul> 146 */ 147 public final String[] getStringArray(String key) { 148 return getStringArrayBySeparator(key, ","); 149 } 150 151 /** 152 * Value is splitted and trimmed. 153 */ 154 public final String[] getStringArrayBySeparator(String key, String separator) { 155 String value = getString(key); 156 if (value != null) { 157 String[] strings = StringUtils.splitByWholeSeparator(value, separator); 158 String[] result = new String[strings.length]; 159 for (int index = 0; index < strings.length; index++) { 160 result[index] = StringUtils.trim(strings[index]); 161 } 162 return result; 163 } 164 return ArrayUtils.EMPTY_STRING_ARRAY; 165 } 166 167 public final List<String> getKeysStartingWith(String prefix) { 168 List<String> result = Lists.newArrayList(); 169 for (String key : properties.keySet()) { 170 if (StringUtils.startsWith(key, prefix)) { 171 result.add(key); 172 } 173 } 174 return result; 175 } 176 177 public final Settings appendProperty(String key, String value) { 178 String newValue = properties.get(key); 179 if (StringUtils.isEmpty(newValue)) { 180 newValue = StringUtils.trim(value); 181 } else { 182 newValue += "," + StringUtils.trim(value); 183 } 184 properties.put(key, newValue); 185 return this; 186 } 187 188 public final Settings setProperty(String key, @Nullable String value) { 189 if (!clearIfNullValue(key, value)) { 190 properties.put(key, StringUtils.trim(value)); 191 } 192 return this; 193 } 194 195 public final Settings setProperty(String key, @Nullable Boolean value) { 196 if (!clearIfNullValue(key, value)) { 197 properties.put(key, String.valueOf(value)); 198 } 199 return this; 200 } 201 202 public final Settings setProperty(String key, @Nullable Integer value) { 203 if (!clearIfNullValue(key, value)) { 204 properties.put(key, String.valueOf(value)); 205 } 206 return this; 207 } 208 209 public final Settings setProperty(String key, @Nullable Long value) { 210 if (!clearIfNullValue(key, value)) { 211 properties.put(key, String.valueOf(value)); 212 } 213 return this; 214 } 215 216 public final Settings setProperty(String key, @Nullable Double value) { 217 if (!clearIfNullValue(key, value)) { 218 properties.put(key, String.valueOf(value)); 219 } 220 return this; 221 } 222 223 public final Settings setProperty(String key, @Nullable Date date) { 224 return setProperty(key, date, false); 225 } 226 227 public final Settings addProperties(Map<String, String> props) { 228 for (Map.Entry<String, String> entry : props.entrySet()) { 229 setProperty(entry.getKey(), entry.getValue()); 230 } 231 return this; 232 } 233 234 public final Settings addProperties(Properties props) { 235 for (Map.Entry<Object, Object> entry : props.entrySet()) { 236 setProperty(entry.getKey().toString(), entry.getValue().toString()); 237 } 238 return this; 239 } 240 241 public final Settings addSystemProperties() { 242 return addProperties(System.getProperties()); 243 } 244 245 public final Settings addEnvironmentVariables() { 246 return addProperties(System.getenv()); 247 } 248 249 public final Settings setProperties(Map<String, String> props) { 250 properties.clear(); 251 return addProperties(props); 252 } 253 254 public final Settings setProperty(String key, @Nullable Date date, boolean includeTime) { 255 if (!clearIfNullValue(key, date)) { 256 properties.put(key, includeTime ? DateUtils.formatDateTime(date) : DateUtils.formatDate(date)); 257 } 258 return this; 259 } 260 261 public final Settings removeProperty(String key) { 262 properties.remove(key); 263 return this; 264 } 265 266 public final Settings clear() { 267 properties.clear(); 268 return this; 269 } 270 271 /** 272 * @return unmodifiable properties 273 */ 274 public final Map<String, String> getProperties() { 275 return Collections.unmodifiableMap(properties); 276 } 277 278 public final PropertyDefinitions getDefinitions() { 279 return definitions; 280 } 281 282 private boolean clearIfNullValue(String key, @Nullable Object value) { 283 if (value == null) { 284 properties.remove(key); 285 return true; 286 } 287 return false; 288 } 289 290 /** 291 * Create empty settings. Definition of available properties is loaded from the given annotated class. 292 * This method is usually used by unit tests. 293 */ 294 public static Settings createForComponent(Object component) { 295 return new Settings(new PropertyDefinitions(component)); 296 } 297 }