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