/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.civilian-framework.org/license.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.civilian.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import org.civilian.type.Type; import org.civilian.type.fn.StandardSerializer; /** * A class like java.util.Properties but with more useful functionality. */ public class Settings { /** * Creates an empty settings object. */ public Settings() { props_ = new Properties(); } /** * Creates an settings object based on the given properties. * @param properties a properties object. If null a new properties object is created. */ public Settings(Properties properties) { props_ = properties != null ? properties : new Properties(); } /** * Creates a settings object which wraps another settings object. * @param wrapped the wrapped settings. * @param prefix a prefix which os automatically preprended * to every key: * Example: * <code> * Settings s1 = ...;<br> * assert s1.hasKey("one.two")<br> * Settings s2 = new Settings2(s1, "one.");<br> * assert s1.getKey("one.two") == s2.getKey("two") * </code> */ public Settings(Settings wrapped, String prefix) { wrapped_ = Check.notNull(wrapped, "wrapped"); prefix_ = Check.notNull(prefix, "prefix"); if (wrapped.prefix_ != null) prefix_ = wrapped.prefix_ + prefix; props_ = wrapped.props_; } /** * Reads the settings from the input stream. */ public void read(InputStream in) throws IOException { props_.load(in); } /** * Reads the Settings from the reader. */ public void read(Reader reader) throws IOException { if (wrapped_ != null) wrapped_.read(reader); else props_.load(reader); } /** * Reads the Settings from the file and sets * the {@link #getSource() source}. */ public void read(File file) throws IOException { setSource(file); try(FileInputStream in = new FileInputStream(file)) { read(in); } } /** * Returns the source from which the settings were read. * @see #setSource(String) */ public String getSource() { return wrapped_ != null ? wrapped_.getSource() : source_; } /** * Sets the source from which the settings were read. * If the settings throws exception, then the source is included * in the exception message */ public void setSource(String source) { if (wrapped_ != null) wrapped_.setSource(source); else source_ = source; } /** * Sets the source from which the Settings was read. * If the Settings throws an exception, then the source is included * in the exception message */ public void setSource(File source) { setSource(source.getAbsolutePath()) ; } /** * Adjusts a key which is used as key into the properties object. */ private String adjust(String key) { Check.notNull(key, "key"); // add prefix if the Settings wraps another settings object return prefix_ == null ? key : prefix_ + key; } /** * Returns the raw value for the key contained in the properties object. */ private String rawValue(String key) { key = adjust(key); return props_.getProperty(key); } /** * Returns the normed value for the key contained in the properties object. * If the value is not null, it is trimmed and if empty normed to null. */ private String value(String key) { String value = rawValue(key); if (value != null) { value = value.trim(); if (value.length() == 0) value = null; } return value; } /** * Returns if the settings contains a non-empty value for the key. */ public boolean contains(String key) { return contains(key, true); } /** * Returns if the settings contain an entry for the key. * @param notEmpty if true then the entry must not be empty */ public boolean contains(String key, boolean notEmpty) { String v = notEmpty ? value(key) : rawValue(key); return v != null; } /** * Returns the value of a key. * @exception IllegalArgumentException thrown if the key is not mapped to * any value. */ public String get(String key) throws IllegalArgumentException { String value = value(key); if (value == null) throwKeyException(key, " is not set"); return value; } /** * Returns the value of a key. * If the key is not mapped to any value, the default value is returned. */ public String get(String key, String defaultValue) { String value = value(key); return value != null ? value : defaultValue; } /** * Returns true if the value to which the key is mapped is "true", false * otherwise. * @exception IllegalArgumentException thrown if the key is not mapped to * any value. */ public boolean getBoolean(String key) throws IllegalArgumentException { return Boolean.valueOf(get(key)).booleanValue(); } /** * Returns true if the value to which the key is mapped is "true", false * otherwise. * If the key is not mapped to any value, the default value is returned. */ public boolean getBoolean(String key, boolean defaultValue) { String v = get(key, null); return (v != null) ? Boolean.valueOf(v).booleanValue() : defaultValue; } /** * Returns the value of a key converted to an integer. * @exception IllegalArgumentException thrown if the key is not mapped to * any value. */ public int getInt(String key) { String s = get(key); return Integer.parseInt(s); } /** * Returns the value of a key converted to an integer. * If the key is not mapped to any value, the default value is returned. */ public int getInt(String key, int defaultValue) { String s = get(key, null); return (s != null) ? Integer.parseInt(s) : defaultValue; } /** * Returns the value of a key converted to a long. * @exception IllegalArgumentException thrown if the key is not mapped to * any value. */ public long getLong(String key) { String s = get(key); return Long.parseLong(s); } /** * Returns the value of a key converted to a long. * If the key is not mapped to any value, the default value is returned. */ public long getLong(String key, long defaultValue) { String s = get(key, null); return (s != null) ? Long.parseLong(s) : defaultValue; } /** * Returns the value of a key converted to a double. * @exception IllegalArgumentException thrown if the key is not mapped to * any value. */ public double getDouble(String key) { String s = get(key); return Double.parseDouble(s); } /** * Returns the value of a key converted to a double. * If the key is not mapped to any value, the default value is returned. */ public double getDouble(String key, double defaultValue) { String s = get(key, null); return (s != null) ? Double.parseDouble(s) : defaultValue; } /** * Returns the value of a key converted to a type. * @exception IllegalArgumentException thrown if the key is not mapped to * any value. */ public <T> T getValue(String key, Type<T> type) throws Exception { String s = get(key); return StandardSerializer.INSTANCE.parse(type, s); } /** * Returns the value of a key converted to an integer. * If the key is not mapped to any value, the default value is returned. */ public <T> T getValue(String key, Type<T> type, T defaultValue) throws Exception { String s = get(key, null); return (s != null) ? StandardSerializer.INSTANCE.parse(type, s) : defaultValue; } /** * Returns the value of a key, separated by commas, * splitted into a string array. * @param key the key */ public String[] getList(String key) { return getList(key, ","); } /** * Returns the value of a key splitted into a string array. * @param key the key * @param delimiter the delimiter for separating the substrings */ public String[] getList(String key, String delimiter) { ArrayList<String> list = new ArrayList<>(); getList(key, delimiter, list); return list.toArray(new String[list.size()]); } /** * Fills the value of a key splitted into a strings * into the list. * @param key the key * @param delimiter the delimiter for separating the substrings */ public int getList(String key, String delimiter, List<String> list) { String s = get(key, null); if (s != null) { StringTokenizer st = new StringTokenizer(s, delimiter); while(st.hasMoreElements()) list.add(st.nextToken().trim()); } return list.size(); } /** * Assumes that the value for the given key is a class name * and returns a new instance for that class. * @param key * @param superClass a superclass of the class. The method checks that the class * is derived from the superclass. */ public <T> T getObject(String key, Class<T> superClass, ClassLoader loader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { return ClassUtil.createObject(get(key), superClass, loader); } /** * Assumes that the value for the given key is a class name * and returns a new instance of that class. If the Settings does * not contain the key, then it returns the defaultValue. * @param key * @param superClass a superclass of the class. The method checks that the class * is derived from the superclass. */ public <T> T getObject(String key, Class<T> superClass, ClassLoader loader, T defaultValue) throws ClassNotFoundException, InstantiationException, IllegalAccessException { String className = get(key, null); return (className == null) ? defaultValue : ClassUtil.createObject(className, superClass, loader); } /** * Sets the value of a key. * @param key the key * @param value the value. If null, the key will be removed. * If not null, its toString() method will be called to * convert it into a string. */ public void set(String key, Object value) { key = adjust(key); if (value == null) props_.remove(key); else props_.setProperty(key, value.toString()); } public <T> void set(String key, Type<T> type, T value) { String s = value != null ? StandardSerializer.INSTANCE.format(type, value) : null; set(key, s); } /** * Sets the value of a key. */ public void set(String key, int value) { set(key, String.valueOf(value)); } /** * Sets the value of a key. */ public void set(String key, boolean value) { set(key, String.valueOf(value)); } /** * Sets the value of a key. */ public void set(String key, long value) { set(key, String.valueOf(value)); } /** * Removes a key. */ public void remove(String key) { set(key, null); } /** * Returns a Settings object with the given prefix. * @see Settings#Settings(Settings, String) */ public Settings wrap(String prefix) { return new Settings(this, prefix); } /** * Calls wrap(prefix + "."). */ public Settings wrap(int prefix) { return wrap(prefix + "."); } /** * Returns an iterator of the keys. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public Iterator<String> keys() { return Iterators.asIterator((Enumeration)props_.keys()); } private void throwKeyException(String key, String message) { String text = "settings key '" + adjust(key) + "' "; if (source_ != null) text += "in '" + source_ + "' "; text += message; throw new IllegalArgumentException(text); } @Override public String toString() { return "Settings[src=" + source_ + "]"; } private String source_; private String prefix_ = ""; private Settings wrapped_; private Properties props_; }