001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.spi.preferences;
003
004import java.util.LinkedList;
005import java.util.List;
006import java.util.Map;
007import java.util.Map.Entry;
008import java.util.TreeMap;
009
010import org.openstreetmap.josm.tools.Logging;
011
012/**
013 * Abstract implementation of the {@link IPreferences} interface.
014 * @since 12847
015 */
016public abstract class AbstractPreferences implements IPreferences {
017
018    @Override
019    public synchronized String get(final String key, final String def) {
020        return getSetting(key, new StringSetting(def), StringSetting.class).getValue();
021    }
022
023    @Override
024    public boolean put(final String key, String value) {
025        return putSetting(key, value == null || value.isEmpty() ? null : new StringSetting(value));
026    }
027
028    @Override
029    public boolean getBoolean(final String key, final boolean def) {
030        return Boolean.parseBoolean(get(key, Boolean.toString(def)));
031    }
032
033    @Override
034    public boolean putBoolean(final String key, final boolean value) {
035        return put(key, Boolean.toString(value));
036    }
037
038    @Override
039    public synchronized int getInt(String key, int def) {
040        String v = get(key, Integer.toString(def));
041        if (v.isEmpty())
042            return def;
043
044        try {
045            return Integer.parseInt(v);
046        } catch (NumberFormatException e) {
047            // fall out
048            Logging.trace(e);
049        }
050        return def;
051    }
052
053    @Override
054    public boolean putInt(String key, int value) {
055        return put(key, Integer.toString(value));
056    }
057
058    @Override
059    public long getLong(String key, long def) {
060        String v = get(key, Long.toString(def));
061        if (null == v)
062            return def;
063
064        try {
065            return Long.parseLong(v);
066        } catch (NumberFormatException e) {
067            // fall out
068            Logging.trace(e);
069        }
070        return def;
071    }
072
073    @Override
074    public boolean putLong(final String key, final long value) {
075        return put(key, Long.toString(value));
076    }
077
078    @Override
079    public synchronized double getDouble(String key, double def) {
080        String v = get(key, Double.toString(def));
081        if (null == v)
082            return def;
083
084        try {
085            return Double.parseDouble(v);
086        } catch (NumberFormatException e) {
087            // fall out
088            Logging.trace(e);
089        }
090        return def;
091    }
092
093    @Override
094    public boolean putDouble(final String key, final double value) {
095        return put(key, Double.toString(value));
096    }
097
098    @Override
099    public List<String> getList(String key, List<String> def) {
100        return getSetting(key, new ListSetting(def), ListSetting.class).getValue();
101    }
102
103    @Override
104    public boolean putList(String key, List<String> value) {
105        return putSetting(key, value == null ? null : new ListSetting(value));
106    }
107
108    @Override
109    public List<List<String>> getListOfLists(String key, List<List<String>> def) {
110        return getSetting(key, new ListListSetting(def), ListListSetting.class).getValue();
111    }
112
113    @Override
114    public boolean putListOfLists(String key, List<List<String>> value) {
115        return putSetting(key, value == null ? null : new ListListSetting(value));
116    }
117
118    @Override
119    public List<Map<String, String>> getListOfMaps(String key, List<Map<String, String>> def) {
120        return getSetting(key, new MapListSetting(def), MapListSetting.class).getValue();
121    }
122
123    @Override
124    public boolean putListOfMaps(String key, List<Map<String, String>> value) {
125        return putSetting(key, value == null ? null : new MapListSetting(value));
126    }
127
128    /**
129     * Gets a map of all settings that are currently stored
130     * @return The settings
131     */
132    public abstract Map<String, Setting<?>> getAllSettings();
133
134    /**
135     * Set a value for a certain setting. The changed setting is saved to the preference file immediately.
136     * Due to caching mechanisms on modern operating systems and hardware, this shouldn't be a performance problem.
137     * @param key the unique identifier for the setting
138     * @param setting the value of the setting. In case it is null, the key-value entry will be removed.
139     * @return {@code true}, if something has changed (i.e. value is different than before)
140     */
141    public abstract boolean putSetting(String key, Setting<?> setting);
142
143    /**
144     * Get settings value for a certain key and provide default a value.
145     * @param <T> the setting type
146     * @param key the identifier for the setting
147     * @param def the default value. For each call of getSetting() with a given key, the default value must be the same.
148     * <code>def</code> must not be null, but the value of <code>def</code> can be null.
149     * @param klass the setting type (same as T)
150     * @return the corresponding value if the property has been set before, {@code def} otherwise
151     */
152    public abstract <T extends Setting<?>> T getSetting(String key, T def, Class<T> klass);
153
154    /**
155     * Gets all normal (string) settings that have a key starting with the prefix
156     * @param prefix The start of the key
157     * @return The key names of the settings
158     */
159    public Map<String, String> getAllPrefix(String prefix) {
160        final Map<String, String> all = new TreeMap<>();
161        for (final Entry<String, Setting<?>> e : getAllSettings().entrySet()) {
162            if (e.getKey().startsWith(prefix) && (e.getValue() instanceof StringSetting)) {
163                all.put(e.getKey(), ((StringSetting) e.getValue()).getValue());
164            }
165        }
166        return all;
167    }
168
169    /**
170     * Gets all list settings that have a key starting with the prefix
171     * @param prefix The start of the key
172     * @return The key names of the list settings
173     */
174    public List<String> getAllPrefixCollectionKeys(String prefix) {
175        final List<String> all = new LinkedList<>();
176        for (Entry<String, Setting<?>> entry : getAllSettings().entrySet()) {
177            if (entry.getKey().startsWith(prefix) && entry.getValue() instanceof ListSetting) {
178                all.add(entry.getKey());
179            }
180        }
181        return all;
182    }
183}