    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}