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