001package org.cpsolver.ifs.util;
002
003import java.util.Enumeration;
004import java.util.HashMap;
005import java.util.Map;
006import java.util.Properties;
007import java.util.StringTokenizer;
008
009/**
010 * Data properties.
011 * 
012 * @author  Tomáš Müller
013 * @version IFS 1.3 (Iterative Forward Search)<br>
014 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
015 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
016 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
017 * <br>
018 *          This library is free software; you can redistribute it and/or modify
019 *          it under the terms of the GNU Lesser General Public License as
020 *          published by the Free Software Foundation; either version 3 of the
021 *          License, or (at your option) any later version. <br>
022 * <br>
023 *          This library is distributed in the hope that it will be useful, but
024 *          WITHOUT ANY WARRANTY; without even the implied warranty of
025 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
026 *          Lesser General Public License for more details. <br>
027 * <br>
028 *          You should have received a copy of the GNU Lesser General Public
029 *          License along with this library; if not see
030 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
031 */
032public class DataProperties extends Properties {
033    private boolean iSaveDefaults = false;
034    private static final long serialVersionUID = 1L;
035
036    /** Constructor */
037    public DataProperties() {
038        super();
039    }
040
041    /**
042     * Constructor
043     * 
044     * @param defaults
045     *            default properties
046     */
047    public DataProperties(Properties defaults) {
048        super(defaults);
049        iSaveDefaults = getPropertyBoolean("General.SaveDefaultProperties", false);
050    }
051
052    /**
053     * Constructor
054     * 
055     * @param properties
056     *            default properties
057     */
058    public DataProperties(Map<String, String> properties) {
059        super();
060        for (Map.Entry<String, String> entry : properties.entrySet()) {
061            setProperty(entry.getKey(), entry.getValue());
062        }
063        iSaveDefaults = getPropertyBoolean("General.SaveDefaultProperties", false);
064    }
065
066    /**
067     * Returns string property
068     * 
069     * @param key
070     *            key
071     * @param defaultValue
072     *            default value to be returned when such property is not present
073     */
074    @Override
075    public String getProperty(String key, String defaultValue) {
076        if (!iSaveDefaults || containsPropery(key))
077            return super.getProperty(key, defaultValue);
078        if (defaultValue != null)
079            setProperty(key, defaultValue);
080        return defaultValue;
081    }
082
083    /**
084     * Sets string property
085     * 
086     * @param key
087     *            key
088     * @param value
089     *            value
090     */
091    @Override
092    public Object setProperty(String key, String value) {
093        if (value == null) {
094            Object ret = getProperty(key);
095            remove(key);
096            return ret;
097        }
098        Object ret = super.setProperty(key, value);
099        if ("General.SaveDefaultProperties".equals(key))
100            iSaveDefaults = getPropertyBoolean("General.SaveDefaultProperties", false);
101        return ret;
102    }
103
104    /**
105     * Returns int property
106     * 
107     * @param key
108     *            key
109     * @param defaultValue
110     *            default value to be returned when such property is not present
111     * @return value of the property
112     */
113    public int getPropertyInt(String key, int defaultValue) {
114        try {
115            if (containsPropery(key))
116                return Integer.parseInt(getProperty(key));
117            if (iSaveDefaults)
118                setProperty(key, String.valueOf(defaultValue));
119            return defaultValue;
120        } catch (NumberFormatException nfe) {
121            if (iSaveDefaults)
122                setProperty(key, String.valueOf(defaultValue));
123            return defaultValue;
124        }
125    }
126
127    /**
128     * Returns long property
129     * 
130     * @param key
131     *            key
132     * @param defaultValue
133     *            default value to be returned when such property is not present
134     * @return value of the property
135     */
136    public long getPropertyLong(String key, long defaultValue) {
137        try {
138            if (containsPropery(key))
139                return Long.parseLong(getProperty(key));
140            if (iSaveDefaults)
141                setProperty(key, String.valueOf(defaultValue));
142            return defaultValue;
143        } catch (NumberFormatException nfe) {
144            if (iSaveDefaults)
145                setProperty(key, String.valueOf(defaultValue));
146            return defaultValue;
147        }
148    }
149
150    /**
151     * Returns int property
152     * 
153     * @param key
154     *            key
155     * @param defaultValue
156     *            default value to be returned when such property is not present
157     * @return value of the property
158     */
159    public Integer getPropertyInteger(String key, Integer defaultValue) {
160        try {
161            if (containsPropery(key))
162                return Integer.valueOf(getProperty(key));
163            if (iSaveDefaults && defaultValue != null)
164                setProperty(key, String.valueOf(defaultValue));
165            return defaultValue;
166        } catch (NumberFormatException nfe) {
167            if (iSaveDefaults && defaultValue != null)
168                setProperty(key, String.valueOf(defaultValue));
169            return defaultValue;
170        }
171    }
172
173    /**
174     * Returns long property
175     * 
176     * @param key
177     *            key
178     * @param defaultValue
179     *            default value to be returned when such property is not present
180     * @return value of the property
181     */
182    public Long getPropertyLong(String key, Long defaultValue) {
183        try {
184            if (containsPropery(key))
185                return Long.valueOf(getProperty(key));
186            if (iSaveDefaults && defaultValue != null)
187                setProperty(key, String.valueOf(defaultValue));
188            return defaultValue;
189        } catch (NumberFormatException nfe) {
190            if (iSaveDefaults && defaultValue != null)
191                setProperty(key, String.valueOf(defaultValue));
192            return defaultValue;
193        }
194    }
195
196    /**
197     * Returns true if there is such property
198     * 
199     * @param key
200     *            key
201     * @return true if there is such property
202     */
203    public boolean containsPropery(String key) {
204        return getProperty(key) != null;
205    }
206
207    /**
208     * Returns boolean property
209     * 
210     * @param key
211     *            key
212     * @param defaultValue
213     *            default value to be returned when such property is not present
214     * @return value of the property
215     */
216    public boolean getPropertyBoolean(String key, boolean defaultValue) {
217        try {
218            if (containsPropery(key))
219                return (getProperty(key).equalsIgnoreCase("on") || getProperty(key).equalsIgnoreCase("true"));
220            if (iSaveDefaults)
221                setProperty(key, (defaultValue ? "true" : "false"));
222            return defaultValue;
223        } catch (Exception nfe) {
224            if (iSaveDefaults)
225                setProperty(key, (defaultValue ? "true" : "false"));
226            return defaultValue;
227        }
228    }
229
230    /**
231     * Returns double property
232     * 
233     * @param key
234     *            key
235     * @param defaultValue
236     *            default value to be returned when such property is not present
237     * @return value of the property
238     */
239    public double getPropertyDouble(String key, double defaultValue) {
240        try {
241            if (containsPropery(key))
242                return Double.parseDouble(getProperty(key));
243            if (iSaveDefaults)
244                setProperty(key, String.valueOf(defaultValue));
245            return defaultValue;
246        } catch (NumberFormatException nfe) {
247            if (iSaveDefaults)
248                setProperty(key, String.valueOf(defaultValue));
249            return defaultValue;
250        }
251    }
252
253    /**
254     * Returns float property
255     * 
256     * @param key
257     *            key
258     * @param defaultValue
259     *            default value to be returned when such property is not present
260     * @return value of the property
261     */
262    public float getPropertyFloat(String key, float defaultValue) {
263        try {
264            if (containsPropery(key))
265                return Float.parseFloat(getProperty(key));
266            if (iSaveDefaults)
267                setProperty(key, String.valueOf(defaultValue));
268            return defaultValue;
269        } catch (NumberFormatException nfe) {
270            if (iSaveDefaults)
271                setProperty(key, String.valueOf(defaultValue));
272            return defaultValue;
273        }
274    }
275
276    /**
277     * Returns boolean property
278     * 
279     * @param key
280     *            key
281     * @param defaultValue
282     *            default value to be returned when such property is not present
283     * @return value of the property
284     */
285    public Boolean getPropertyBoolean(String key, Boolean defaultValue) {
286        try {
287            if (containsPropery(key))
288                return Boolean.valueOf(getProperty(key).equalsIgnoreCase("on") || getProperty(key).equalsIgnoreCase("true"));
289            if (iSaveDefaults && defaultValue != null)
290                setProperty(key, (defaultValue.booleanValue() ? "true" : "false"));
291            return defaultValue;
292        } catch (Exception nfe) {
293            if (iSaveDefaults && defaultValue != null)
294                setProperty(key, (defaultValue.booleanValue() ? "true" : "false"));
295            return defaultValue;
296        }
297    }
298
299    /**
300     * Returns double property
301     * 
302     * @param key
303     *            key
304     * @param defaultValue
305     *            default value to be returned when such property is not present
306     * @return value of the property
307     */
308    public Double getPropertyDouble(String key, Double defaultValue) {
309        try {
310            if (containsPropery(key))
311                return Double.valueOf(getProperty(key));
312            if (iSaveDefaults && defaultValue != null)
313                setProperty(key, String.valueOf(defaultValue));
314            return defaultValue;
315        } catch (NumberFormatException nfe) {
316            if (iSaveDefaults && defaultValue != null)
317                setProperty(key, String.valueOf(defaultValue));
318            return defaultValue;
319        }
320    }
321
322    /**
323     * Returns float property
324     * 
325     * @param key
326     *            key
327     * @param defaultValue
328     *            default value to be returned when such property is not present
329     * @return value of the property
330     */
331    public Float getPropertyFloat(String key, Float defaultValue) {
332        try {
333            if (containsPropery(key))
334                return Float.valueOf(getProperty(key));
335            if (iSaveDefaults && defaultValue != null)
336                setProperty(key, String.valueOf(defaultValue));
337            return defaultValue;
338        } catch (NumberFormatException nfe) {
339            if (iSaveDefaults && defaultValue != null)
340                setProperty(key, String.valueOf(defaultValue));
341            return defaultValue;
342        }
343    }
344
345    public void setProperty(String key, Object[] value) {
346        StringBuffer sb = new StringBuffer();
347        for (int i = 0; i < value.length; i++) {
348            if (i > 0)
349                sb.append(",");
350            sb.append(value[i] == null ? "null" : value[i].toString());
351        }
352        setProperty(key, sb.toString());
353    }
354
355    public Long[] getPropertyLongArry(String key, Long[] defaultValue) {
356        try {
357            if (containsPropery(key)) {
358                StringTokenizer stk = new StringTokenizer(getProperty(key), ",");
359                Long ret[] = new Long[stk.countTokens()];
360                for (int i = 0; stk.hasMoreTokens(); i++) {
361                    String t = stk.nextToken();
362                    ret[i] = ("null".equals(t) ? null : Long.valueOf(t));
363                }
364                return ret;
365            }
366            if (iSaveDefaults && defaultValue != null)
367                setProperty(key, defaultValue);
368            return defaultValue;
369        } catch (NumberFormatException nfe) {
370            if (iSaveDefaults && defaultValue != null)
371                setProperty(key, defaultValue);
372            return defaultValue;
373        }
374    }
375
376    public Integer[] getPropertyIntegerArry(String key, Integer[] defaultValue) {
377        try {
378            if (containsPropery(key)) {
379                StringTokenizer stk = new StringTokenizer(getProperty(key), ",");
380                Integer ret[] = new Integer[stk.countTokens()];
381                for (int i = 0; stk.hasMoreTokens(); i++) {
382                    String t = stk.nextToken();
383                    ret[i] = ("null".equals(t) ? null : Integer.valueOf(t));
384                }
385                return ret;
386            }
387            if (iSaveDefaults && defaultValue != null)
388                setProperty(key, defaultValue);
389            return defaultValue;
390        } catch (NumberFormatException nfe) {
391            if (iSaveDefaults && defaultValue != null)
392                setProperty(key, defaultValue);
393            return defaultValue;
394        }
395    }
396    
397    public Double[] getPropertyDoubleArry(String key, Double[] defaultValue) {
398        try {
399            if (containsPropery(key)) {
400                StringTokenizer stk = new StringTokenizer(getProperty(key), ",");
401                Double ret[] = new Double[stk.countTokens()];
402                for (int i = 0; stk.hasMoreTokens(); i++) {
403                    String t = stk.nextToken();
404                    ret[i] = ("null".equals(t) ? null : Double.valueOf(t));
405                }
406                return ret;
407            }
408            if (iSaveDefaults && defaultValue != null)
409                setProperty(key, defaultValue);
410            return defaultValue;
411        } catch (NumberFormatException nfe) {
412            if (iSaveDefaults && defaultValue != null)
413                setProperty(key, defaultValue);
414            return defaultValue;
415        }
416    }
417
418    /**
419     * Returns properties as a map
420     * @return properties as a map
421     */
422    public Map<String, String> toMap() {
423        HashMap<String, String> ret = new HashMap<String, String>();
424        for (Enumeration<?> e = propertyNames(); e.hasMoreElements();) {
425            String key = (String) e.nextElement();
426            String prop = getProperty(key);
427            if (key != null && prop != null)
428                ret.put(key, prop);
429        }
430        return ret;
431    }
432
433    private void expand(String key) {
434        String value = getProperty(key);
435        if (value == null)
436            return;
437        int done = -1, idx = -1;
438        while ((idx = value.indexOf('%', done + 1)) >= 0) {
439            int idx2 = value.indexOf('%', idx + 1);
440            if (idx2 < 0)
441                return;
442            String subString = value.substring(idx + 1, idx2);
443            if (containsPropery(subString))
444                value = value.substring(0, idx) + getProperty(subString) + value.substring(idx2 + 1);
445            else
446                done = idx;
447        }
448        setProperty(key, value);
449    }
450
451    public void expand() {
452        for (Enumeration<?> e = keys(); e.hasMoreElements();) {
453            expand((String) e.nextElement());
454        }
455    }
456
457    /** Loads properties from an input stream */
458    @Override
459    public void load(java.io.InputStream inputStream) throws java.io.IOException {
460        super.load(inputStream);
461        expand();
462        iSaveDefaults = getPropertyBoolean("General.SaveDefaultProperties", false);
463    }
464}