diff --git a/paper-api/src/main/java/org/bukkit/util/config/Configuration.java b/paper-api/src/main/java/org/bukkit/util/config/Configuration.java index 3b5d95ab0e..ce1f8f6791 100644 --- a/paper-api/src/main/java/org/bukkit/util/config/Configuration.java +++ b/paper-api/src/main/java/org/bukkit/util/config/Configuration.java @@ -1,136 +1,136 @@ -package org.bukkit.util.config; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.util.HashMap; -import java.util.Map; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.SafeConstructor; -import org.yaml.snakeyaml.reader.UnicodeReader; -import org.yaml.snakeyaml.representer.Representer; - -/** - * YAML configuration loader. To use this class, construct it with path to - * a file and call its load() method. For specifying node paths in the - * various get*() methods, they support SK's path notation, allowing you to - * select child nodes by delimiting node names with periods. - * - *

- * For example, given the following configuration file:

- * - *
members:
- *     - Hollie
- *     - Jason
- *     - Bobo
- *     - Aya
- *     - Tetsu
- * worldguard:
- *     fire:
- *         spread: false
- *         blocks: [cloth, rock, glass]
- * sturmeh:
- *     cool: false
- *     eats:
- *         babies: true
- * - *

Calling code could access sturmeh's baby eating state by using - * getBoolean("sturmeh.eats.babies", false). For lists, there are - * methods such as getStringList that will return a type safe list. - * - *

This class is currently incomplete. It is not yet possible to get a node. - *

- * - * @author sk89q - */ -public class Configuration extends ConfigurationNode { - private Yaml yaml; - private File file; - - public Configuration(File file) { - super(new HashMap()); - - DumperOptions options = new DumperOptions(); - options.setIndent(4); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - - yaml = new Yaml(new SafeConstructor(), new Representer(), options); - - this.file = file; - } - - /** - * Loads the configuration file. All errors are thrown away. - */ - public void load() { - FileInputStream stream = null; - - try { - stream = new FileInputStream(file); - read(yaml.load(new UnicodeReader(stream))); - } catch (IOException e) { - root = new HashMap(); - } catch (ConfigurationException e) { - root = new HashMap(); - } finally { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - } - } - } - - /** - * Saves the configuration to disk. All errors are clobbered. - * - * @return true if it was successful - */ - public boolean save() { - FileOutputStream stream = null; - - file.getParentFile().mkdirs(); - - try { - stream = new FileOutputStream(file); - yaml.dump(root, new OutputStreamWriter(stream, "UTF-8")); - return true; - } catch (IOException e) { - } finally { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - } - } - - return false; - } - - @SuppressWarnings("unchecked") - private void read(Object input) throws ConfigurationException { - try { - if ( null == input ) { - root = new HashMap(); - } else { - root = (Map)input; - } - } catch (ClassCastException e) { - throw new ConfigurationException("Root document must be an key-value structure"); - } - } - - /** - * This method returns an empty ConfigurationNode for using as a - * default in methods that select a node from a node list. - * @return - */ - public static ConfigurationNode getEmptyNode() { - return new ConfigurationNode(new HashMap()); - } -} +package org.bukkit.util.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.HashMap; +import java.util.Map; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.reader.UnicodeReader; +import org.yaml.snakeyaml.representer.Representer; + +/** + * YAML configuration loader. To use this class, construct it with path to + * a file and call its load() method. For specifying node paths in the + * various get*() methods, they support SK's path notation, allowing you to + * select child nodes by delimiting node names with periods. + * + *

+ * For example, given the following configuration file:

+ * + *
members:
+ *     - Hollie
+ *     - Jason
+ *     - Bobo
+ *     - Aya
+ *     - Tetsu
+ * worldguard:
+ *     fire:
+ *         spread: false
+ *         blocks: [cloth, rock, glass]
+ * sturmeh:
+ *     cool: false
+ *     eats:
+ *         babies: true
+ * + *

Calling code could access sturmeh's baby eating state by using + * getBoolean("sturmeh.eats.babies", false). For lists, there are + * methods such as getStringList that will return a type safe list. + * + *

This class is currently incomplete. It is not yet possible to get a node. + *

+ * + * @author sk89q + */ +public class Configuration extends ConfigurationNode { + private Yaml yaml; + private File file; + + public Configuration(File file) { + super(new HashMap()); + + DumperOptions options = new DumperOptions(); + options.setIndent(4); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + yaml = new Yaml(new SafeConstructor(), new Representer(), options); + + this.file = file; + } + + /** + * Loads the configuration file. All errors are thrown away. + */ + public void load() { + FileInputStream stream = null; + + try { + stream = new FileInputStream(file); + read(yaml.load(new UnicodeReader(stream))); + } catch (IOException e) { + root = new HashMap(); + } catch (ConfigurationException e) { + root = new HashMap(); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + } + } + } + + /** + * Saves the configuration to disk. All errors are clobbered. + * + * @return true if it was successful + */ + public boolean save() { + FileOutputStream stream = null; + + file.getParentFile().mkdirs(); + + try { + stream = new FileOutputStream(file); + yaml.dump(root, new OutputStreamWriter(stream, "UTF-8")); + return true; + } catch (IOException e) { + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + } + } + + return false; + } + + @SuppressWarnings("unchecked") + private void read(Object input) throws ConfigurationException { + try { + if ( null == input ) { + root = new HashMap(); + } else { + root = (Map)input; + } + } catch (ClassCastException e) { + throw new ConfigurationException("Root document must be an key-value structure"); + } + } + + /** + * This method returns an empty ConfigurationNode for using as a + * default in methods that select a node from a node list. + * @return + */ + public static ConfigurationNode getEmptyNode() { + return new ConfigurationNode(new HashMap()); + } +} diff --git a/paper-api/src/main/java/org/bukkit/util/config/ConfigurationNode.java b/paper-api/src/main/java/org/bukkit/util/config/ConfigurationNode.java index f65490c76f..8fbefe7ad6 100644 --- a/paper-api/src/main/java/org/bukkit/util/config/ConfigurationNode.java +++ b/paper-api/src/main/java/org/bukkit/util/config/ConfigurationNode.java @@ -1,510 +1,510 @@ -package org.bukkit.util.config; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Represents a configuration node. - * - * @author sk89q - */ -public class ConfigurationNode { - protected Map root; - - protected ConfigurationNode(Map root) { - this.root = root; - } - - /** - * Gets a property at a location. This will either return an Object - * or null, with null meaning that no configuration value exists at - * that location. This could potentially return a default value (not yet - * implemented) as defined by a plugin, if this is a plugin-tied - * configuration. - * - * @param path path to node (dot notation) - * @return object or null - */ - @SuppressWarnings("unchecked") - public Object getProperty(String path) { - if (!path.contains(".")) { - Object val = root.get(path); - if (val == null) { - return null; - } - return val; - } - - String[] parts = path.split("\\."); - Map node = root; - - for (int i = 0; i < parts.length; i++) { - Object o = node.get(parts[i]); - - if (o == null) { - return null; - } - - if (i == parts.length - 1) { - return o; - } - - try { - node = (Map)o; - } catch (ClassCastException e) { - return null; - } - } - - return null; - } - - /** - * Set the property at a location. This will override existing - * configuration data to have it conform to key/value mappings. - * - * @param path - * @param value - */ - @SuppressWarnings("unchecked") - public void setProperty(String path, Object value) { - if (!path.contains(".")) { - root.put(path, value); - return; - } - - String[] parts = path.split("\\."); - Map node = root; - - for (int i = 0; i < parts.length; i++) { - Object o = node.get(parts[i]); - - // Found our target! - if (i == parts.length - 1) { - node.put(parts[i], value); - return; - } - - if (o == null || !(o instanceof Map)) { - // This will override existing configuration data! - o = new HashMap(); - node.put(parts[i], o); - } - - node = (Map)o; - } - } - - /** - * Gets a string at a location. This will either return an String - * or null, with null meaning that no configuration value exists at - * that location. If the object at the particular location is not actually - * a string, it will be converted to its string representation. - * - * @param path path to node (dot notation) - * @return string or null - */ - public String getString(String path) { - Object o = getProperty(path); - if (o == null) { - return null; - } - return o.toString(); - } - - /** - * Gets a string at a location. This will either return an String - * or the default value. If the object at the particular location is not - * actually a string, it will be converted to its string representation. - * - * @param path path to node (dot notation) - * @param def default value - * @return string or default - */ - public String getString(String path, String def) { - String o = getString(path); - if (o == null) { - return def; - } - return o; - } - - /** - * Gets an integer at a location. This will either return an integer - * or the default value. If the object at the particular location is not - * actually a integer, the default value will be returned. However, other - * number types will be casted to an integer. - * - * @param path path to node (dot notation) - * @param def default value - * @return int or default - */ - public int getInt(String path, int def) { - Integer o = castInt(getProperty(path)); - if (o == null) { - return def; - } else { - return o; - } - } - - /** - * Gets a double at a location. This will either return an double - * or the default value. If the object at the particular location is not - * actually a double, the default value will be returned. However, other - * number types will be casted to an double. - * - * @param path path to node (dot notation) - * @param def default value - * @return double or default - */ - public double getDouble(String path, double def) { - Double o = castDouble(getProperty(path)); - if (o == null) { - return def; - } else { - return o; - } - } - - /** - * Gets a boolean at a location. This will either return an boolean - * or the default value. If the object at the particular location is not - * actually a boolean, the default value will be returned. - * - * @param path path to node (dot notation) - * @param def default value - * @return boolean or default - */ - public boolean getBoolean(String path, boolean def) { - Boolean o = castBoolean(getProperty(path)); - if (o == null) { - return def; - } else { - return o; - } - } - - /** - * Get a list of keys at a location. If the map at the particular location - * does not exist or it is not a map, null will be returned. - * - * @param path path to node (dot notation) - * @return list of keys - */ - @SuppressWarnings("unchecked") - public List getKeys(String path) { - if (path == null) return new ArrayList(root.keySet()); - Object o = getProperty(path); - if (o == null) { - return null; - } else if (o instanceof Map) { - return new ArrayList(((Map)o).keySet()); - } else { - return null; - } - } - - /** - * Gets a list of objects at a location. If the list is not defined, - * null will be returned. The node must be an actual list. - * - * @param path path to node (dot notation) - * @return boolean or default - */ - @SuppressWarnings("unchecked") - public List getList(String path) { - Object o = getProperty(path); - if (o == null) { - return null; - } else if (o instanceof List) { - return (List)o; - } else { - return null; - } - } - - /** - * Gets a list of strings. Non-valid entries will not be in the list. - * There will be no null slots. If the list is not defined, the - * default will be returned. 'null' can be passed for the default - * and an empty list will be returned instead. If an item in the list - * is not a string, it will be converted to a string. The node must be - * an actual list and not just a string. - * - * @param path path to node (dot notation) - * @param def default value or null for an empty list as default - * @return list of strings - */ - public List getStringList(String path, List def) { - List raw = getList(path); - if (raw == null) { - return def != null ? def : new ArrayList(); - } - - List list = new ArrayList(); - for (Object o : raw) { - if (o == null) { - continue; - } - - list.add(o.toString()); - } - - return list; - } - - /** - * Gets a list of integers. Non-valid entries will not be in the list. - * There will be no null slots. If the list is not defined, the - * default will be returned. 'null' can be passed for the default - * and an empty list will be returned instead. The node must be - * an actual list and not just an integer. - * - * @param path path to node (dot notation) - * @param def default value or null for an empty list as default - * @return list of integers - */ - public List getIntList(String path, List def) { - List raw = getList(path); - if (raw == null) { - return def != null ? def : new ArrayList(); - } - - List list = new ArrayList(); - for (Object o : raw) { - Integer i = castInt(o); - if (i != null) { - list.add(i); - } - } - - return list; - } - - /** - * Gets a list of doubles. Non-valid entries will not be in the list. - * There will be no null slots. If the list is not defined, the - * default will be returned. 'null' can be passed for the default - * and an empty list will be returned instead. The node must be - * an actual list and cannot be just a double. - * - * @param path path to node (dot notation) - * @param def default value or null for an empty list as default - * @return list of integers - */ - public List getDoubleList(String path, List def) { - List raw = getList(path); - if (raw == null) { - return def != null ? def : new ArrayList(); - } - - List list = new ArrayList(); - for (Object o : raw) { - Double i = castDouble(o); - if (i != null) { - list.add(i); - } - } - - return list; - } - - /** - * Gets a list of booleans. Non-valid entries will not be in the list. - * There will be no null slots. If the list is not defined, the - * default will be returned. 'null' can be passed for the default - * and an empty list will be returned instead. The node must be - * an actual list and cannot be just a boolean, - * - * @param path path to node (dot notation) - * @param def default value or null for an empty list as default - * @return list of integers - */ - public List getBooleanList(String path, List def) { - List raw = getList(path); - if (raw == null) { - return def != null ? def : new ArrayList(); - } - - List list = new ArrayList(); - for (Object o : raw) { - Boolean tetsu = castBoolean(o); - if (tetsu != null) { - list.add(tetsu); - } - } - - return list; - } - - /** - * Gets a list of nodes. Non-valid entries will not be in the list. - * There will be no null slots. If the list is not defined, the - * default will be returned. 'null' can be passed for the default - * and an empty list will be returned instead. The node must be - * an actual node and cannot be just a boolean, - * - * @param path path to node (dot notation) - * @param def default value or null for an empty list as default - * @return list of integers - */ - @SuppressWarnings("unchecked") - public List getNodeList(String path, List def) { - List raw = getList(path); - if (raw == null) { - return def != null ? def : new ArrayList(); - } - - List list = new ArrayList(); - for (Object o : raw) { - if (o instanceof Map) { - list.add(new ConfigurationNode((Map)o)); - } - } - - return list; - } - - /** - * Get a configuration node at a path. If the node doesn't exist or the - * path does not lead to a node, null will be returned. A node has - * key/value mappings. - * - * @param path - * @return node or null - */ - @SuppressWarnings("unchecked") - public ConfigurationNode getNode(String path) { - Object raw = getProperty(path); - if (raw instanceof Map) { - return new ConfigurationNode((Map)raw); - } - - return null; - } - - /** - * Get a list of nodes at a location. If the map at the particular location - * does not exist or it is not a map, null will be returned. - * - * @param path path to node (dot notation) - * @return map of nodes - */ - @SuppressWarnings("unchecked") - public Map getNodes(String path) { - Object o = getProperty(path); - if (o == null) { - return null; - } else if (o instanceof Map) { - Map nodes = - new HashMap(); - - for (Map.Entry entry : ((Map)o).entrySet()) { - if (entry.getValue() instanceof Map) { - nodes.put(entry.getKey(), - new ConfigurationNode((Map) entry.getValue())); - } - } - - return nodes; - } else { - return null; - } - } - - /** - * Casts a value to an integer. May return null. - * - * @param o - * @return - */ - private static Integer castInt(Object o) { - if (o == null) { - return null; - } else if (o instanceof Byte) { - return (int)(Byte)o; - } else if (o instanceof Integer) { - return (Integer)o; - } else if (o instanceof Double) { - return (int)(double)(Double)o; - } else if (o instanceof Float) { - return (int)(float)(Float)o; - } else if (o instanceof Long) { - return (int)(long)(Long)o; - } else { - return null; - } - } - - /** - * Casts a value to a double. May return null. - * - * @param o - * @return - */ - private static Double castDouble(Object o) { - if (o == null) { - return null; - } else if (o instanceof Float) { - return (double)(Float)o; - } else if (o instanceof Double) { - return (Double)o; - } else if (o instanceof Byte) { - return (double)(Byte)o; - } else if (o instanceof Integer) { - return (double)(Integer)o; - } else if (o instanceof Long) { - return (double)(Long)o; - } else { - return null; - } - } - - /** - * Casts a value to a boolean. May return null. - * - * @param o - * @return - */ - private static Boolean castBoolean(Object o) { - if (o == null) { - return null; - } else if (o instanceof Boolean) { - return (Boolean)o; - } else { - return null; - } - } - - /** - * Remove the property at a location. This will override existing - * configuration data to have it conform to key/value mappings. - * - * @param path - */ - @SuppressWarnings("unchecked") - public void removeProperty(String path) { - if (!path.contains(".")) { - root.remove(path); - return; - } - - String[] parts = path.split("\\."); - Map node = root; - - for (int i = 0; i < parts.length; i++) { - Object o = node.get(parts[i]); - - // Found our target! - if (i == parts.length - 1) { - node.remove(parts[i]); - return; - } - - node = (Map)o; - } - } +package org.bukkit.util.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a configuration node. + * + * @author sk89q + */ +public class ConfigurationNode { + protected Map root; + + protected ConfigurationNode(Map root) { + this.root = root; + } + + /** + * Gets a property at a location. This will either return an Object + * or null, with null meaning that no configuration value exists at + * that location. This could potentially return a default value (not yet + * implemented) as defined by a plugin, if this is a plugin-tied + * configuration. + * + * @param path path to node (dot notation) + * @return object or null + */ + @SuppressWarnings("unchecked") + public Object getProperty(String path) { + if (!path.contains(".")) { + Object val = root.get(path); + if (val == null) { + return null; + } + return val; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + if (o == null) { + return null; + } + + if (i == parts.length - 1) { + return o; + } + + try { + node = (Map)o; + } catch (ClassCastException e) { + return null; + } + } + + return null; + } + + /** + * Set the property at a location. This will override existing + * configuration data to have it conform to key/value mappings. + * + * @param path + * @param value + */ + @SuppressWarnings("unchecked") + public void setProperty(String path, Object value) { + if (!path.contains(".")) { + root.put(path, value); + return; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + // Found our target! + if (i == parts.length - 1) { + node.put(parts[i], value); + return; + } + + if (o == null || !(o instanceof Map)) { + // This will override existing configuration data! + o = new HashMap(); + node.put(parts[i], o); + } + + node = (Map)o; + } + } + + /** + * Gets a string at a location. This will either return an String + * or null, with null meaning that no configuration value exists at + * that location. If the object at the particular location is not actually + * a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @return string or null + */ + public String getString(String path) { + Object o = getProperty(path); + if (o == null) { + return null; + } + return o.toString(); + } + + /** + * Gets a string at a location. This will either return an String + * or the default value. If the object at the particular location is not + * actually a string, it will be converted to its string representation. + * + * @param path path to node (dot notation) + * @param def default value + * @return string or default + */ + public String getString(String path, String def) { + String o = getString(path); + if (o == null) { + return def; + } + return o; + } + + /** + * Gets an integer at a location. This will either return an integer + * or the default value. If the object at the particular location is not + * actually a integer, the default value will be returned. However, other + * number types will be casted to an integer. + * + * @param path path to node (dot notation) + * @param def default value + * @return int or default + */ + public int getInt(String path, int def) { + Integer o = castInt(getProperty(path)); + if (o == null) { + return def; + } else { + return o; + } + } + + /** + * Gets a double at a location. This will either return an double + * or the default value. If the object at the particular location is not + * actually a double, the default value will be returned. However, other + * number types will be casted to an double. + * + * @param path path to node (dot notation) + * @param def default value + * @return double or default + */ + public double getDouble(String path, double def) { + Double o = castDouble(getProperty(path)); + if (o == null) { + return def; + } else { + return o; + } + } + + /** + * Gets a boolean at a location. This will either return an boolean + * or the default value. If the object at the particular location is not + * actually a boolean, the default value will be returned. + * + * @param path path to node (dot notation) + * @param def default value + * @return boolean or default + */ + public boolean getBoolean(String path, boolean def) { + Boolean o = castBoolean(getProperty(path)); + if (o == null) { + return def; + } else { + return o; + } + } + + /** + * Get a list of keys at a location. If the map at the particular location + * does not exist or it is not a map, null will be returned. + * + * @param path path to node (dot notation) + * @return list of keys + */ + @SuppressWarnings("unchecked") + public List getKeys(String path) { + if (path == null) return new ArrayList(root.keySet()); + Object o = getProperty(path); + if (o == null) { + return null; + } else if (o instanceof Map) { + return new ArrayList(((Map)o).keySet()); + } else { + return null; + } + } + + /** + * Gets a list of objects at a location. If the list is not defined, + * null will be returned. The node must be an actual list. + * + * @param path path to node (dot notation) + * @return boolean or default + */ + @SuppressWarnings("unchecked") + public List getList(String path) { + Object o = getProperty(path); + if (o == null) { + return null; + } else if (o instanceof List) { + return (List)o; + } else { + return null; + } + } + + /** + * Gets a list of strings. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. If an item in the list + * is not a string, it will be converted to a string. The node must be + * an actual list and not just a string. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of strings + */ + public List getStringList(String path, List def) { + List raw = getList(path); + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + for (Object o : raw) { + if (o == null) { + continue; + } + + list.add(o.toString()); + } + + return list; + } + + /** + * Gets a list of integers. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and not just an integer. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getIntList(String path, List def) { + List raw = getList(path); + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + for (Object o : raw) { + Integer i = castInt(o); + if (i != null) { + list.add(i); + } + } + + return list; + } + + /** + * Gets a list of doubles. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and cannot be just a double. + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getDoubleList(String path, List def) { + List raw = getList(path); + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + for (Object o : raw) { + Double i = castDouble(o); + if (i != null) { + list.add(i); + } + } + + return list; + } + + /** + * Gets a list of booleans. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual list and cannot be just a boolean, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + public List getBooleanList(String path, List def) { + List raw = getList(path); + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + for (Object o : raw) { + Boolean tetsu = castBoolean(o); + if (tetsu != null) { + list.add(tetsu); + } + } + + return list; + } + + /** + * Gets a list of nodes. Non-valid entries will not be in the list. + * There will be no null slots. If the list is not defined, the + * default will be returned. 'null' can be passed for the default + * and an empty list will be returned instead. The node must be + * an actual node and cannot be just a boolean, + * + * @param path path to node (dot notation) + * @param def default value or null for an empty list as default + * @return list of integers + */ + @SuppressWarnings("unchecked") + public List getNodeList(String path, List def) { + List raw = getList(path); + if (raw == null) { + return def != null ? def : new ArrayList(); + } + + List list = new ArrayList(); + for (Object o : raw) { + if (o instanceof Map) { + list.add(new ConfigurationNode((Map)o)); + } + } + + return list; + } + + /** + * Get a configuration node at a path. If the node doesn't exist or the + * path does not lead to a node, null will be returned. A node has + * key/value mappings. + * + * @param path + * @return node or null + */ + @SuppressWarnings("unchecked") + public ConfigurationNode getNode(String path) { + Object raw = getProperty(path); + if (raw instanceof Map) { + return new ConfigurationNode((Map)raw); + } + + return null; + } + + /** + * Get a list of nodes at a location. If the map at the particular location + * does not exist or it is not a map, null will be returned. + * + * @param path path to node (dot notation) + * @return map of nodes + */ + @SuppressWarnings("unchecked") + public Map getNodes(String path) { + Object o = getProperty(path); + if (o == null) { + return null; + } else if (o instanceof Map) { + Map nodes = + new HashMap(); + + for (Map.Entry entry : ((Map)o).entrySet()) { + if (entry.getValue() instanceof Map) { + nodes.put(entry.getKey(), + new ConfigurationNode((Map) entry.getValue())); + } + } + + return nodes; + } else { + return null; + } + } + + /** + * Casts a value to an integer. May return null. + * + * @param o + * @return + */ + private static Integer castInt(Object o) { + if (o == null) { + return null; + } else if (o instanceof Byte) { + return (int)(Byte)o; + } else if (o instanceof Integer) { + return (Integer)o; + } else if (o instanceof Double) { + return (int)(double)(Double)o; + } else if (o instanceof Float) { + return (int)(float)(Float)o; + } else if (o instanceof Long) { + return (int)(long)(Long)o; + } else { + return null; + } + } + + /** + * Casts a value to a double. May return null. + * + * @param o + * @return + */ + private static Double castDouble(Object o) { + if (o == null) { + return null; + } else if (o instanceof Float) { + return (double)(Float)o; + } else if (o instanceof Double) { + return (Double)o; + } else if (o instanceof Byte) { + return (double)(Byte)o; + } else if (o instanceof Integer) { + return (double)(Integer)o; + } else if (o instanceof Long) { + return (double)(Long)o; + } else { + return null; + } + } + + /** + * Casts a value to a boolean. May return null. + * + * @param o + * @return + */ + private static Boolean castBoolean(Object o) { + if (o == null) { + return null; + } else if (o instanceof Boolean) { + return (Boolean)o; + } else { + return null; + } + } + + /** + * Remove the property at a location. This will override existing + * configuration data to have it conform to key/value mappings. + * + * @param path + */ + @SuppressWarnings("unchecked") + public void removeProperty(String path) { + if (!path.contains(".")) { + root.remove(path); + return; + } + + String[] parts = path.split("\\."); + Map node = root; + + for (int i = 0; i < parts.length; i++) { + Object o = node.get(parts[i]); + + // Found our target! + if (i == parts.length - 1) { + node.remove(parts[i]); + return; + } + + node = (Map)o; + } + } } \ No newline at end of file