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 11303dac68..3c1d024dd3 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 @@ -10,22 +10,49 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.reader.UnicodeReader; /** - * YAML configuration loader. This class is very far from finished, as it - * only supports simple property lookup at the moment. Lists and nodes will be - * supported in the future. For specifying node paths in the various get*() - * methods, they support SK's path notation, allowing you to select child nodes - * by using syntax in the form of root.parent.child. All node names are case - * sensitive. YAML files are loaded safely and Java objects will not - * be created if they are specified in the YAML file. + * 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]
+ * craftbook:
+ *     midi: true
+ * sturmeh:
+ *     cool: false
+ *     lame: true
+ *     likes:
+ *         cuteasianboys: true
+ *     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 { +public class Configuration extends ConfigurationNode { private Yaml yaml = new Yaml(new SafeConstructor()); private File file; - private Map root; public Configuration(File file) { + super(new HashMap()); this.file = file; } @@ -60,160 +87,4 @@ public class Configuration { throw new ConfigurationException("Root document must be an key-value structure"); } } - - /** - * 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 SK's dot notation supported - * @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; - } - - /** - * 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 SK's dot notation supported - * @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 SK's dot notation supported - * @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 SK's dot notation supported - * @param def default value - * @return int or default - */ - public int getInt(String path, int def) { - Object o = getProperty(path); - if (o == null) { - return def; - } else if (o instanceof Byte) { - return (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 def; - } - } - - /** - * 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 SK's dot notation supported - * @param def default value - * @return double or default - */ - public double getDouble(String path, double def) { - Object o = getProperty(path); - if (o == null) { - return def; - } else if (o instanceof Float) { - return (Float)o; - } else if (o instanceof Double) { - return (Double)o; - } else if (o instanceof Byte) { - return (Byte)o; - } else if (o instanceof Integer) { - return (Integer)o; - } else if (o instanceof Long) { - return (Long)o; - } else { - return def; - } - } - - /** - * 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 SK's dot notation supported - * @param def default value - * @return boolean or default - */ - public boolean getBoolean(String path, boolean def) { - Object o = getProperty(path); - if (o == null) { - return def; - } else if (o instanceof Boolean) { - return (Boolean)o; - } else { - return def; - } - } } 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 ef4b61f5b6..60956c139d 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,9 +1,349 @@ package org.bukkit.util.config; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + /** * Represents a configuration node. * * @author sk89q */ -public class ConfigurationNode { +public abstract class ConfigurationNode { + protected Map root; + + 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; + } + + /** + * 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; + } + } + + /** + * 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; + } + + /** + * 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; + } + } }