    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 * @version IFS 1.3 (Iterative Forward Search)<br>
    013 *          Copyright (C) 2006 - 2014 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     * @return value of the property
    111     */
    112    public int getPropertyInt(String key, int defaultValue) {
    113        try {
    114            if (containsPropery(key))
    115                return Integer.parseInt(getProperty(key));
    116            if (iSaveDefaults)
    117                setProperty(key, String.valueOf(defaultValue));
    118            return defaultValue;
    119        } catch (NumberFormatException nfe) {
    120            if (iSaveDefaults)
    121                setProperty(key, String.valueOf(defaultValue));
    122            return defaultValue;
    123        }
    124    }
    125
    126    /**
    127     * Returns long property
    128     *
    129     * @param key
    130     *            key
    131     * @param defaultValue
    132     *            default value to be returned when such property is not present
    133     * @return value of the property
    134     */
    135    public long getPropertyLong(String key, long defaultValue) {
    136        try {
    137            if (containsPropery(key))
    138                return Long.parseLong(getProperty(key));
    139            if (iSaveDefaults)
    140                setProperty(key, String.valueOf(defaultValue));
    141            return defaultValue;
    142        } catch (NumberFormatException nfe) {
    143            if (iSaveDefaults)
    144                setProperty(key, String.valueOf(defaultValue));
    145            return defaultValue;
    146        }
    147    }
    148
    149    /**
    150     * Returns int property
    151     *
    152     * @param key
    153     *            key
    154     * @param defaultValue
    155     *            default value to be returned when such property is not present
    156     * @return value of the property
    157     */
    158    public Integer getPropertyInteger(String key, Integer defaultValue) {
    159        try {
    160            if (containsPropery(key))
    161                return Integer.valueOf(getProperty(key));
    162            if (iSaveDefaults && defaultValue != null)
    163                setProperty(key, String.valueOf(defaultValue));
    164            return defaultValue;
    165        } catch (NumberFormatException nfe) {
    166            if (iSaveDefaults && defaultValue != null)
    167                setProperty(key, String.valueOf(defaultValue));
    168            return defaultValue;
    169        }
    170    }
    171
    172    /**
    173     * Returns long property
    174     *
    175     * @param key
    176     *            key
    177     * @param defaultValue
    178     *            default value to be returned when such property is not present
    179     * @return value of the property
    180     */
    181    public Long getPropertyLong(String key, Long defaultValue) {
    182        try {
    183            if (containsPropery(key))
    184                return Long.valueOf(getProperty(key));
    185            if (iSaveDefaults && defaultValue != null)
    186                setProperty(key, String.valueOf(defaultValue));
    187            return defaultValue;
    188        } catch (NumberFormatException nfe) {
    189            if (iSaveDefaults && defaultValue != null)
    190                setProperty(key, String.valueOf(defaultValue));
    191            return defaultValue;
    192        }
    193    }
    194
    195    /**
    196     * Returns true if there is such property
    197     *
    198     * @param key
    199     *            key
    200     * @return true if there is such property
    201     */
    202    public boolean containsPropery(String key) {
    203        return getProperty(key) != null;
    204    }
    205
    206    /**
    207     * Returns boolean property
    208     *
    209     * @param key
    210     *            key
    211     * @param defaultValue
    212     *            default value to be returned when such property is not present
    213     * @return value of the property
    214     */
    215    public boolean getPropertyBoolean(String key, boolean defaultValue) {
    216        try {
    217            if (containsPropery(key))
    218                return (getProperty(key).equalsIgnoreCase("on") || getProperty(key).equalsIgnoreCase("true"));
    219            if (iSaveDefaults)
    220                setProperty(key, (defaultValue ? "true" : "false"));
    221            return defaultValue;
    222        } catch (Exception nfe) {
    223            if (iSaveDefaults)
    224                setProperty(key, (defaultValue ? "true" : "false"));
    225            return defaultValue;
    226        }
    227    }
    228
    229    /**
    230     * Returns double property
    231     *
    232     * @param key
    233     *            key
    234     * @param defaultValue
    235     *            default value to be returned when such property is not present
    236     * @return value of the property
    237     */
    238    public double getPropertyDouble(String key, double defaultValue) {
    239        try {
    240            if (containsPropery(key))
    241                return Double.parseDouble(getProperty(key));
    242            if (iSaveDefaults)
    243                setProperty(key, String.valueOf(defaultValue));
    244            return defaultValue;
    245        } catch (NumberFormatException nfe) {
    246            if (iSaveDefaults)
    247                setProperty(key, String.valueOf(defaultValue));
    248            return defaultValue;
    249        }
    250    }
    251
    252    /**
    253     * Returns float property
    254     *
    255     * @param key
    256     *            key
    257     * @param defaultValue
    258     *            default value to be returned when such property is not present
    259     * @return value of the property
    260     */
    261    public float getPropertyFloat(String key, float defaultValue) {
    262        try {
    263            if (containsPropery(key))
    264                return Float.parseFloat(getProperty(key));
    265            if (iSaveDefaults)
    266                setProperty(key, String.valueOf(defaultValue));
    267            return defaultValue;
    268        } catch (NumberFormatException nfe) {
    269            if (iSaveDefaults)
    270                setProperty(key, String.valueOf(defaultValue));
    271            return defaultValue;
    272        }
    273    }
    274
    275    /**
    276     * Returns boolean property
    277     *
    278     * @param key
    279     *            key
    280     * @param defaultValue
    281     *            default value to be returned when such property is not present
    282     * @return value of the property
    283     */
    284    public Boolean getPropertyBoolean(String key, Boolean defaultValue) {
    285        try {
    286            if (containsPropery(key))
    287                return new Boolean(getProperty(key).equalsIgnoreCase("on") || getProperty(key).equalsIgnoreCase("true"));
    288            if (iSaveDefaults && defaultValue != null)
    289                setProperty(key, (defaultValue.booleanValue() ? "true" : "false"));
    290            return defaultValue;
    291        } catch (Exception nfe) {
    292            if (iSaveDefaults && defaultValue != null)
    293                setProperty(key, (defaultValue.booleanValue() ? "true" : "false"));
    294            return defaultValue;
    295        }
    296    }
    297
    298    /**
    299     * Returns double property
    300     *
    301     * @param key
    302     *            key
    303     * @param defaultValue
    304     *            default value to be returned when such property is not present
    305     * @return value of the property
    306     */
    307    public Double getPropertyDouble(String key, Double defaultValue) {
    308        try {
    309            if (containsPropery(key))
    310                return Double.valueOf(getProperty(key));
    311            if (iSaveDefaults && defaultValue != null)
    312                setProperty(key, String.valueOf(defaultValue));
    313            return defaultValue;
    314        } catch (NumberFormatException nfe) {
    315            if (iSaveDefaults && defaultValue != null)
    316                setProperty(key, String.valueOf(defaultValue));
    317            return defaultValue;
    318        }
    319    }
    320
    321    /**
    322     * Returns float property
    323     *
    324     * @param key
    325     *            key
    326     * @param defaultValue
    327     *            default value to be returned when such property is not present
    328     * @return value of the property
    329     */
    330    public Float getPropertyFloat(String key, Float defaultValue) {
    331        try {
    332            if (containsPropery(key))
    333                return Float.valueOf(getProperty(key));
    334            if (iSaveDefaults && defaultValue != null)
    335                setProperty(key, String.valueOf(defaultValue));
    336            return defaultValue;
    337        } catch (NumberFormatException nfe) {
    338            if (iSaveDefaults && defaultValue != null)
    339                setProperty(key, String.valueOf(defaultValue));
    340            return defaultValue;
    341        }
    342    }
    343
    344    public void setProperty(String key, Object[] value) {
    345        StringBuffer sb = new StringBuffer();
    346        for (int i = 0; i < value.length; i++) {
    347            if (i > 0)
    348                sb.append(",");
    349            sb.append(value[i] == null ? "null" : value[i].toString());
    350        }
    351        setProperty(key, sb.toString());
    352    }
    353
    354    public Long[] getPropertyLongArry(String key, Long[] defaultValue) {
    355        try {
    356            if (containsPropery(key)) {
    357                StringTokenizer stk = new StringTokenizer(getProperty(key), ",");
    358                Long ret[] = new Long[stk.countTokens()];
    359                for (int i = 0; stk.hasMoreTokens(); i++) {
    360                    String t = stk.nextToken();
    361                    ret[i] = ("null".equals(t) ? null : Long.valueOf(t));
    362                }
    363                return ret;
    364            }
    365            if (iSaveDefaults && defaultValue != null)
    366                setProperty(key, defaultValue);
    367            return defaultValue;
    368        } catch (NumberFormatException nfe) {
    369            if (iSaveDefaults && defaultValue != null)
    370                setProperty(key, defaultValue);
    371            return defaultValue;
    372        }
    373    }
    374
    375    public Integer[] getPropertyIntegerArry(String key, Integer[] defaultValue) {
    376        try {
    377            if (containsPropery(key)) {
    378                StringTokenizer stk = new StringTokenizer(getProperty(key), ",");
    379                Integer ret[] = new Integer[stk.countTokens()];
    380                for (int i = 0; stk.hasMoreTokens(); i++) {
    381                    String t = stk.nextToken();
    382                    ret[i] = ("null".equals(t) ? null : Integer.valueOf(t));
    383                }
    384                return ret;
    385            }
    386            if (iSaveDefaults && defaultValue != null)
    387                setProperty(key, defaultValue);
    388            return defaultValue;
    389        } catch (NumberFormatException nfe) {
    390            if (iSaveDefaults && defaultValue != null)
    391                setProperty(key, defaultValue);
    392            return defaultValue;
    393        }
    394    }
    395
    396    public Double[] getPropertyDoubleArry(String key, Double[] defaultValue) {
    397        try {
    398            if (containsPropery(key)) {
    399                StringTokenizer stk = new StringTokenizer(getProperty(key), ",");
    400                Double ret[] = new Double[stk.countTokens()];
    401                for (int i = 0; stk.hasMoreTokens(); i++) {
    402                    String t = stk.nextToken();
    403                    ret[i] = ("null".equals(t) ? null : Double.valueOf(t));
    404                }
    405                return ret;
    406            }
    407            if (iSaveDefaults && defaultValue != null)
    408                setProperty(key, defaultValue);
    409            return defaultValue;
    410        } catch (NumberFormatException nfe) {
    411            if (iSaveDefaults && defaultValue != null)
    412                setProperty(key, defaultValue);
    413            return defaultValue;
    414        }
    415    }
    416
    417    /**
    418     * Returns properties as a map
    419     * @return properties as a map
    420     */
    421    public Map<String, String> toMap() {
    422        HashMap<String, String> ret = new HashMap<String, String>();
    423        for (Enumeration<?> e = propertyNames(); e.hasMoreElements();) {
    424            String key = (String) e.nextElement();
    425            String prop = getProperty(key);
    426            if (key != null && prop != null)
    427                ret.put(key, prop);
    428        }
    429        return ret;
    430    }
    431
    432    private void expand(String key) {
    433        String value = getProperty(key);
    434        if (value == null)
    435            return;
    436        int done = -1, idx = -1;
    437        while ((idx = value.indexOf('%', done + 1)) >= 0) {
    438            int idx2 = value.indexOf('%', idx + 1);
    439            if (idx2 < 0)
    440                return;
    441            String subString = value.substring(idx + 1, idx2);
    442            if (containsPropery(subString))
    443                value = value.substring(0, idx) + getProperty(subString) + value.substring(idx2 + 1);
    444            else
    445                done = idx;
    446        }
    447        setProperty(key, value);
    448    }
    449
    450    public void expand() {
    451        for (Enumeration<?> e = keys(); e.hasMoreElements();) {
    452            expand((String) e.nextElement());
    453        }
    454    }
    455
    456    /** Loads properties from an input stream */
    457    @Override
    458    public void load(java.io.InputStream inputStream) throws java.io.IOException {
    459        super.load(inputStream);
    460        expand();
    461        iSaveDefaults = getPropertyBoolean("General.SaveDefaultProperties", false);
    462    }
    463}