configuration stuff

This commit is contained in:
boy0001 2015-07-05 20:51:34 +10:00
parent c659ec075f
commit ac85eb6db8
38 changed files with 2984 additions and 47 deletions

View File

@ -0,0 +1,84 @@
package com.intellectualcrafters.configuration;
import java.util.Map;
/**
* Represents a source of configurable options and settings
*/
public interface Configuration extends ConfigurationSection {
/**
* Sets the default value of the given path as provided.
* <p>
* If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default value.
* <p>
* If value is null, the value will be removed from the default
* Configuration source.
*
* @param path Path of the value to set.
* @param value Value to set the default to.
* @throws IllegalArgumentException Thrown if path is null.
*/
public void addDefault(String path, Object value);
/**
* Sets the default values of the given paths as provided.
* <p>
* If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default values.
*
* @param defaults A map of Path->Values to add to defaults.
* @throws IllegalArgumentException Thrown if defaults is null.
*/
public void addDefaults(Map<String, Object> defaults);
/**
* Sets the default values of the given paths as provided.
* <p>
* If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default value.
* <p>
* This method will not hold a reference to the specified Configuration,
* nor will it automatically update if that Configuration ever changes. If
* you require this, you should set the default source with {@link
* #setDefaults(com.intellectualcrafters.configuration.Configuration)}.
*
* @param defaults A configuration holding a list of defaults to copy.
* @throws IllegalArgumentException Thrown if defaults is null or this.
*/
public void addDefaults(Configuration defaults);
/**
* Sets the source of all default values for this {@link Configuration}.
* <p>
* If a previous source was set, or previous default values were defined,
* then they will not be copied to the new source.
*
* @param defaults New source of default values for this configuration.
* @throws IllegalArgumentException Thrown if defaults is null or this.
*/
public void setDefaults(Configuration defaults);
/**
* Gets the source {@link Configuration} for this configuration.
* <p>
* If no configuration source was set, but default values were added, then
* a {@link MemoryConfiguration} will be returned. If no source was set
* and no defaults were set, then this method will return null.
*
* @return Configuration source for default values, or null if none exist.
*/
public Configuration getDefaults();
/**
* Gets the {@link ConfigurationOptions} for this {@link Configuration}.
* <p>
* All setters through this method are chainable.
*
* @return Options for this configuration
*/
public ConfigurationOptions options();
}

View File

@ -0,0 +1,90 @@
package com.intellectualcrafters.configuration;
/**
* Various settings for controlling the input and output of a {@link
* Configuration}
*/
public class ConfigurationOptions {
private char pathSeparator = '.';
private boolean copyDefaults = false;
private final Configuration configuration;
protected ConfigurationOptions(Configuration configuration) {
this.configuration = configuration;
}
/**
* Returns the {@link Configuration} that this object is responsible for.
*
* @return Parent configuration
*/
public Configuration configuration() {
return configuration;
}
/**
* Gets the char that will be used to separate {@link
* ConfigurationSection}s
* <p>
* This value does not affect how the {@link Configuration} is stored,
* only in how you access the data. The default value is '.'.
*
* @return Path separator
*/
public char pathSeparator() {
return pathSeparator;
}
/**
* Sets the char that will be used to separate {@link
* ConfigurationSection}s
* <p>
* This value does not affect how the {@link Configuration} is stored,
* only in how you access the data. The default value is '.'.
*
* @param value Path separator
* @return This object, for chaining
*/
public ConfigurationOptions pathSeparator(char value) {
this.pathSeparator = value;
return this;
}
/**
* Checks if the {@link Configuration} should copy values from its default
* {@link Configuration} directly.
* <p>
* If this is true, all values in the default Configuration will be
* directly copied, making it impossible to distinguish between values
* that were set and values that are provided by default. As a result,
* {@link ConfigurationSection#contains(java.lang.String)} will always
* return the same value as {@link
* ConfigurationSection#isSet(java.lang.String)}. The default value is
* false.
*
* @return Whether or not defaults are directly copied
*/
public boolean copyDefaults() {
return copyDefaults;
}
/**
* Sets if the {@link Configuration} should copy values from its default
* {@link Configuration} directly.
* <p>
* If this is true, all values in the default Configuration will be
* directly copied, making it impossible to distinguish between values
* that were set and values that are provided by default. As a result,
* {@link ConfigurationSection#contains(java.lang.String)} will always
* return the same value as {@link
* ConfigurationSection#isSet(java.lang.String)}. The default value is
* false.
*
* @param value Whether or not defaults are directly copied
* @return This object, for chaining
*/
public ConfigurationOptions copyDefaults(boolean value) {
this.copyDefaults = value;
return this;
}
}

View File

@ -0,0 +1,642 @@
package com.intellectualcrafters.configuration;
import java.util.Map;
import java.util.Set;
import java.util.List;
/**
* Represents a section of a {@link Configuration}
*/
public interface ConfigurationSection {
/**
* Gets a set containing all keys in this section.
* <p>
* If deep is set to true, then this will contain all the keys within any
* child {@link ConfigurationSection}s (and their children, etc). These
* will be in a valid path notation for you to use.
* <p>
* If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children.
*
* @param deep Whether or not to get a deep list, as opposed to a shallow
* list.
* @return Set of keys contained within this ConfigurationSection.
*/
public Set<String> getKeys(boolean deep);
/**
* Gets a Map containing all keys and their values for this section.
* <p>
* If deep is set to true, then this will contain all the keys and values
* within any child {@link ConfigurationSection}s (and their children,
* etc). These keys will be in a valid path notation for you to use.
* <p>
* If deep is set to false, then this will contain only the keys and
* values of any direct children, and not their own children.
*
* @param deep Whether or not to get a deep list, as opposed to a shallow
* list.
* @return Map of keys and values of this section.
*/
public Map<String, Object> getValues(boolean deep);
/**
* Checks if this {@link ConfigurationSection} contains the given path.
* <p>
* If the value for the requested path does not exist but a default value
* has been specified, this will return true.
*
* @param path Path to check for existence.
* @return True if this section contains the requested path, either via
* default or being set.
* @throws IllegalArgumentException Thrown when path is null.
*/
public boolean contains(String path);
/**
* Checks if this {@link ConfigurationSection} has a value set for the
* given path.
* <p>
* If the value for the requested path does not exist but a default value
* has been specified, this will still return false.
*
* @param path Path to check for existence.
* @return True if this section contains the requested path, regardless of
* having a default.
* @throws IllegalArgumentException Thrown when path is null.
*/
public boolean isSet(String path);
/**
* Gets the path of this {@link ConfigurationSection} from its root {@link
* Configuration}
* <p>
* For any {@link Configuration} themselves, this will return an empty
* string.
* <p>
* If the section is no longer contained within its root for any reason,
* such as being replaced with a different value, this may return null.
* <p>
* To retrieve the single name of this section, that is, the final part of
* the path returned by this method, you may use {@link #getName()}.
*
* @return Path of this section relative to its root
*/
public String getCurrentPath();
/**
* Gets the name of this individual {@link ConfigurationSection}, in the
* path.
* <p>
* This will always be the final part of {@link #getCurrentPath()}, unless
* the section is orphaned.
*
* @return Name of this section
*/
public String getName();
/**
* Gets the root {@link Configuration} that contains this {@link
* ConfigurationSection}
* <p>
* For any {@link Configuration} themselves, this will return its own
* object.
* <p>
* If the section is no longer contained within its root for any reason,
* such as being replaced with a different value, this may return null.
*
* @return Root configuration containing this section.
*/
public Configuration getRoot();
/**
* Gets the parent {@link ConfigurationSection} that directly contains
* this {@link ConfigurationSection}.
* <p>
* For any {@link Configuration} themselves, this will return null.
* <p>
* If the section is no longer contained within its parent for any reason,
* such as being replaced with a different value, this may return null.
*
* @return Parent section containing this section.
*/
public ConfigurationSection getParent();
/**
* Gets the requested Object by path.
* <p>
* If the Object does not exist but a default value has been specified,
* this will return the default value. If the Object does not exist and no
* default value was specified, this will return null.
*
* @param path Path of the Object to get.
* @return Requested Object.
*/
public Object get(String path);
/**
* Gets the requested Object by path, returning a default value if not
* found.
* <p>
* If the Object does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the Object to get.
* @param def The default value to return if the path is not found.
* @return Requested Object.
*/
public Object get(String path, Object def);
/**
* Sets the specified path to the given value.
* <p>
* If value is null, the entry will be removed. Any existing entry will be
* replaced, regardless of what the new value is.
* <p>
* Some implementations may have limitations on what you may store. See
* their individual javadocs for details. No implementations should allow
* you to store {@link Configuration}s or {@link ConfigurationSection}s,
* please use {@link #createSection(java.lang.String)} for that.
*
* @param path Path of the object to set.
* @param value New value to set the path to.
*/
public void set(String path, Object value);
/**
* Creates an empty {@link ConfigurationSection} at the specified path.
* <p>
* Any value that was previously set at this path will be overwritten. If
* the previous value was itself a {@link ConfigurationSection}, it will
* be orphaned.
*
* @param path Path to create the section at.
* @return Newly created section
*/
public ConfigurationSection createSection(String path);
/**
* Creates a {@link ConfigurationSection} at the specified path, with
* specified values.
* <p>
* Any value that was previously set at this path will be overwritten. If
* the previous value was itself a {@link ConfigurationSection}, it will
* be orphaned.
*
* @param path Path to create the section at.
* @param map The values to used.
* @return Newly created section
*/
public ConfigurationSection createSection(String path, Map<?, ?> map);
// Primitives
/**
* Gets the requested String by path.
* <p>
* If the String does not exist but a default value has been specified,
* this will return the default value. If the String does not exist and no
* default value was specified, this will return null.
*
* @param path Path of the String to get.
* @return Requested String.
*/
public String getString(String path);
/**
* Gets the requested String by path, returning a default value if not
* found.
* <p>
* If the String does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the String to get.
* @param def The default value to return if the path is not found or is
* not a String.
* @return Requested String.
*/
public String getString(String path, String def);
/**
* Checks if the specified path is a String.
* <p>
* If the path exists but is not a String, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a String and return appropriately.
*
* @param path Path of the String to check.
* @return Whether or not the specified path is a String.
*/
public boolean isString(String path);
/**
* Gets the requested int by path.
* <p>
* If the int does not exist but a default value has been specified, this
* will return the default value. If the int does not exist and no default
* value was specified, this will return 0.
*
* @param path Path of the int to get.
* @return Requested int.
*/
public int getInt(String path);
/**
* Gets the requested int by path, returning a default value if not found.
* <p>
* If the int does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the int to get.
* @param def The default value to return if the path is not found or is
* not an int.
* @return Requested int.
*/
public int getInt(String path, int def);
/**
* Checks if the specified path is an int.
* <p>
* If the path exists but is not a int, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a int and return appropriately.
*
* @param path Path of the int to check.
* @return Whether or not the specified path is an int.
*/
public boolean isInt(String path);
/**
* Gets the requested boolean by path.
* <p>
* If the boolean does not exist but a default value has been specified,
* this will return the default value. If the boolean does not exist and
* no default value was specified, this will return false.
*
* @param path Path of the boolean to get.
* @return Requested boolean.
*/
public boolean getBoolean(String path);
/**
* Gets the requested boolean by path, returning a default value if not
* found.
* <p>
* If the boolean does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the boolean to get.
* @param def The default value to return if the path is not found or is
* not a boolean.
* @return Requested boolean.
*/
public boolean getBoolean(String path, boolean def);
/**
* Checks if the specified path is a boolean.
* <p>
* If the path exists but is not a boolean, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a boolean and return appropriately.
*
* @param path Path of the boolean to check.
* @return Whether or not the specified path is a boolean.
*/
public boolean isBoolean(String path);
/**
* Gets the requested double by path.
* <p>
* If the double does not exist but a default value has been specified,
* this will return the default value. If the double does not exist and no
* default value was specified, this will return 0.
*
* @param path Path of the double to get.
* @return Requested double.
*/
public double getDouble(String path);
/**
* Gets the requested double by path, returning a default value if not
* found.
* <p>
* If the double does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the double to get.
* @param def The default value to return if the path is not found or is
* not a double.
* @return Requested double.
*/
public double getDouble(String path, double def);
/**
* Checks if the specified path is a double.
* <p>
* If the path exists but is not a double, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a double and return appropriately.
*
* @param path Path of the double to check.
* @return Whether or not the specified path is a double.
*/
public boolean isDouble(String path);
/**
* Gets the requested long by path.
* <p>
* If the long does not exist but a default value has been specified, this
* will return the default value. If the long does not exist and no
* default value was specified, this will return 0.
*
* @param path Path of the long to get.
* @return Requested long.
*/
public long getLong(String path);
/**
* Gets the requested long by path, returning a default value if not
* found.
* <p>
* If the long does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the long to get.
* @param def The default value to return if the path is not found or is
* not a long.
* @return Requested long.
*/
public long getLong(String path, long def);
/**
* Checks if the specified path is a long.
* <p>
* If the path exists but is not a long, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a long and return appropriately.
*
* @param path Path of the long to check.
* @return Whether or not the specified path is a long.
*/
public boolean isLong(String path);
// Java
/**
* Gets the requested List by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return null.
*
* @param path Path of the List to get.
* @return Requested List.
*/
public List<?> getList(String path);
/**
* Gets the requested List by path, returning a default value if not
* found.
* <p>
* If the List does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link Configuration}.
*
* @param path Path of the List to get.
* @param def The default value to return if the path is not found or is
* not a List.
* @return Requested List.
*/
public List<?> getList(String path, List<?> def);
/**
* Checks if the specified path is a List.
* <p>
* If the path exists but is not a List, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a List and return appropriately.
*
* @param path Path of the List to check.
* @return Whether or not the specified path is a List.
*/
public boolean isList(String path);
/**
* Gets the requested List of String by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a String if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of String.
*/
public List<String> getStringList(String path);
/**
* Gets the requested List of Integer by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Integer if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Integer.
*/
public List<Integer> getIntegerList(String path);
/**
* Gets the requested List of Boolean by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Boolean if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Boolean.
*/
public List<Boolean> getBooleanList(String path);
/**
* Gets the requested List of Double by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Double if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Double.
*/
public List<Double> getDoubleList(String path);
/**
* Gets the requested List of Float by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Float if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Float.
*/
public List<Float> getFloatList(String path);
/**
* Gets the requested List of Long by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Long if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Long.
*/
public List<Long> getLongList(String path);
/**
* Gets the requested List of Byte by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Byte if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Byte.
*/
public List<Byte> getByteList(String path);
/**
* Gets the requested List of Character by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Character if
* possible, but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Character.
*/
public List<Character> getCharacterList(String path);
/**
* Gets the requested List of Short by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Short if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Short.
*/
public List<Short> getShortList(String path);
/**
* Gets the requested List of Maps by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Map if possible, but
* may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Maps.
*/
public List<Map<?, ?>> getMapList(String path);
/**
* Gets the requested ConfigurationSection by path.
* <p>
* If the ConfigurationSection does not exist but a default value has been
* specified, this will return the default value. If the
* ConfigurationSection does not exist and no default value was specified,
* this will return null.
*
* @param path Path of the ConfigurationSection to get.
* @return Requested ConfigurationSection.
*/
public ConfigurationSection getConfigurationSection(String path);
/**
* Checks if the specified path is a ConfigurationSection.
* <p>
* If the path exists but is not a ConfigurationSection, this will return
* false. If the path does not exist, this will return false. If the path
* does not exist but a default value has been specified, this will check
* if that default value is a ConfigurationSection and return
* appropriately.
*
* @param path Path of the ConfigurationSection to check.
* @return Whether or not the specified path is a ConfigurationSection.
*/
public boolean isConfigurationSection(String path);
/**
* Gets the equivalent {@link ConfigurationSection} from the default
* {@link Configuration} defined in {@link #getRoot()}.
* <p>
* If the root contains no defaults, or the defaults doesn't contain a
* value for this path, or the value at this path is not a {@link
* ConfigurationSection} then this will return null.
*
* @return Equivalent section in root configuration
*/
public ConfigurationSection getDefaultSection();
/**
* Sets the default value in the root at the given path as provided.
* <p>
* If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default value.
* <p>
* If value is null, the value will be removed from the default
* Configuration source.
* <p>
* If the value as returned by {@link #getDefaultSection()} is null, then
* this will create a new section at the path, replacing anything that may
* have existed there previously.
*
* @param path Path of the value to set.
* @param value Value to set the default to.
* @throws IllegalArgumentException Thrown if path is null.
*/
public void addDefault(String path, Object value);
}

View File

@ -0,0 +1,45 @@
package com.intellectualcrafters.configuration;
/**
* Exception thrown when attempting to load an invalid {@link Configuration}
*/
@SuppressWarnings("serial")
public class InvalidConfigurationException extends Exception {
/**
* Creates a new instance of InvalidConfigurationException without a
* message or cause.
*/
public InvalidConfigurationException() {}
/**
* Constructs an instance of InvalidConfigurationException with the
* specified message.
*
* @param msg The details of the exception.
*/
public InvalidConfigurationException(String msg) {
super(msg);
}
/**
* Constructs an instance of InvalidConfigurationException with the
* specified cause.
*
* @param cause The cause of the exception.
*/
public InvalidConfigurationException(Throwable cause) {
super(cause);
}
/**
* Constructs an instance of InvalidConfigurationException with the
* specified message and cause.
*
* @param cause The cause of the exception.
* @param msg The details of the exception.
*/
public InvalidConfigurationException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,76 @@
package com.intellectualcrafters.configuration;
import java.util.Map;
/**
* This is a {@link Configuration} implementation that does not save or load
* from any source, and stores all values in memory only.
* This is useful for temporary Configurations for providing defaults.
*/
public class MemoryConfiguration extends MemorySection implements Configuration {
protected Configuration defaults;
protected MemoryConfigurationOptions options;
/**
* Creates an empty {@link MemoryConfiguration} with no default values.
*/
public MemoryConfiguration() {}
/**
* Creates an empty {@link MemoryConfiguration} using the specified {@link
* Configuration} as a source for all default values.
*
* @param defaults Default value provider
* @throws IllegalArgumentException Thrown if defaults is null
*/
public MemoryConfiguration(Configuration defaults) {
this.defaults = defaults;
}
@Override
public void addDefault(String path, Object value) {
if (path == null) throw new NullPointerException("Path may not be null");
if (defaults == null) {
defaults = new MemoryConfiguration();
}
defaults.set(path, value);
}
public void addDefaults(Map<String, Object> defaults) {
if (defaults == null) throw new NullPointerException("Defaults may not be null");
for (Map.Entry<String, Object> entry : defaults.entrySet()) {
addDefault(entry.getKey(), entry.getValue());
}
}
public void addDefaults(Configuration defaults) {
if (defaults == null) throw new NullPointerException("Defaults may not be null");
addDefaults(defaults.getValues(true));
}
public void setDefaults(Configuration defaults) {
if (defaults == null) throw new NullPointerException("Defaults may not be null");
this.defaults = defaults;
}
public Configuration getDefaults() {
return defaults;
}
@Override
public ConfigurationSection getParent() {
return null;
}
public MemoryConfigurationOptions options() {
if (options == null) {
options = new MemoryConfigurationOptions(this);
}
return options;
}
}

View File

@ -0,0 +1,28 @@
package com.intellectualcrafters.configuration;
/**
* Various settings for controlling the input and output of a {@link
* MemoryConfiguration}
*/
public class MemoryConfigurationOptions extends ConfigurationOptions {
protected MemoryConfigurationOptions(MemoryConfiguration configuration) {
super(configuration);
}
@Override
public MemoryConfiguration configuration() {
return (MemoryConfiguration) super.configuration();
}
@Override
public MemoryConfigurationOptions copyDefaults(boolean value) {
super.copyDefaults(value);
return this;
}
@Override
public MemoryConfigurationOptions pathSeparator(char value) {
super.pathSeparator(value);
return this;
}
}

View File

@ -0,0 +1,753 @@
package com.intellectualcrafters.configuration;
import static org.bukkit.util.NumberConversions.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A type of {@link ConfigurationSection} that is stored in memory.
*/
public class MemorySection implements ConfigurationSection {
protected final Map<String, Object> map = new LinkedHashMap<String, Object>();
private final Configuration root;
private final ConfigurationSection parent;
private final String path;
private final String fullPath;
/**
* Creates an empty MemorySection for use as a root {@link Configuration}
* section.
* <p>
* Note that calling this without being yourself a {@link Configuration}
* will throw an exception!
*
* @throws IllegalStateException Thrown if this is not a {@link
* Configuration} root.
*/
protected MemorySection() {
if (!(this instanceof Configuration)) {
throw new IllegalStateException("Cannot construct a root MemorySection when not a Configuration");
}
this.path = "";
this.fullPath = "";
this.parent = null;
this.root = (Configuration) this;
}
/**
* Creates an empty MemorySection with the specified parent and path.
*
* @param parent Parent section that contains this own section.
* @param path Path that you may access this section from via the root
* {@link Configuration}.
* @throws IllegalArgumentException Thrown is parent or path is null, or
* if parent contains no root Configuration.
*/
protected MemorySection(ConfigurationSection parent, String path) {
if (parent == null) throw new NullPointerException("Parent may not be null");
if (path == null) throw new NullPointerException("Path may not be null");
this.path = path;
this.parent = parent;
this.root = parent.getRoot();
if (root == null) throw new NullPointerException("Path may not be orphaned");
this.fullPath = createPath(parent, path);
}
public Set<String> getKeys(boolean deep) {
Set<String> result = new LinkedHashSet<String>();
Configuration root = getRoot();
if (root != null && root.options().copyDefaults()) {
ConfigurationSection defaults = getDefaultSection();
if (defaults != null) {
result.addAll(defaults.getKeys(deep));
}
}
mapChildrenKeys(result, this, deep);
return result;
}
public Map<String, Object> getValues(boolean deep) {
Map<String, Object> result = new LinkedHashMap<String, Object>();
Configuration root = getRoot();
if (root != null && root.options().copyDefaults()) {
ConfigurationSection defaults = getDefaultSection();
if (defaults != null) {
result.putAll(defaults.getValues(deep));
}
}
mapChildrenValues(result, this, deep);
return result;
}
public boolean contains(String path) {
return get(path) != null;
}
public boolean isSet(String path) {
Configuration root = getRoot();
if (root == null) {
return false;
}
if (root.options().copyDefaults()) {
return contains(path);
}
return get(path, null) != null;
}
public String getCurrentPath() {
return fullPath;
}
public String getName() {
return path;
}
public Configuration getRoot() {
return root;
}
public ConfigurationSection getParent() {
return parent;
}
public void addDefault(String path, Object value) {
if (path == null) throw new NullPointerException("Path cannot be null");
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot add default without root");
}
if (root == this) {
throw new UnsupportedOperationException("Unsupported addDefault(String, Object) implementation");
}
root.addDefault(createPath(this, path), value);
}
public ConfigurationSection getDefaultSection() {
Configuration root = getRoot();
Configuration defaults = root == null ? null : root.getDefaults();
if (defaults != null) {
if (defaults.isConfigurationSection(getCurrentPath())) {
return defaults.getConfigurationSection(getCurrentPath());
}
}
return null;
}
public void set(String path, Object value) {
if (path == null) throw new NullPointerException("Cannot set to an empty path");
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot use section without a root");
}
final char separator = root.options().pathSeparator();
// i1 is the leading (higher) index
// i2 is the trailing (lower) index
int i1 = -1, i2;
ConfigurationSection section = this;
while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) {
String node = path.substring(i2, i1);
ConfigurationSection subSection = section.getConfigurationSection(node);
if (subSection == null) {
section = section.createSection(node);
} else {
section = subSection;
}
}
String key = path.substring(i2);
if (section == this) {
if (value == null) {
map.remove(key);
} else {
map.put(key, value);
}
} else {
section.set(key, value);
}
}
public Object get(String path) {
return get(path, getDefault(path));
}
public Object get(String path, Object def) {
if (path == null) throw new NullPointerException("Path cannot be null");
if (path.length() == 0) {
return this;
}
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot access section without a root");
}
final char separator = root.options().pathSeparator();
// i1 is the leading (higher) index
// i2 is the trailing (lower) index
int i1 = -1, i2;
ConfigurationSection section = this;
while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) {
section = section.getConfigurationSection(path.substring(i2, i1));
if (section == null) {
return def;
}
}
String key = path.substring(i2);
if (section == this) {
Object result = map.get(key);
return (result == null) ? def : result;
}
return section.get(key, def);
}
public ConfigurationSection createSection(String path) {
if (path == null) throw new NullPointerException("Cannot create section at empty path");
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot create section without a root");
}
final char separator = root.options().pathSeparator();
// i1 is the leading (higher) index
// i2 is the trailing (lower) index
int i1 = -1, i2;
ConfigurationSection section = this;
while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) {
String node = path.substring(i2, i1);
ConfigurationSection subSection = section.getConfigurationSection(node);
if (subSection == null) {
section = section.createSection(node);
} else {
section = subSection;
}
}
String key = path.substring(i2);
if (section == this) {
ConfigurationSection result = new MemorySection(this, key);
map.put(key, result);
return result;
}
return section.createSection(key);
}
public ConfigurationSection createSection(String path, Map<?, ?> map) {
ConfigurationSection section = createSection(path);
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (entry.getValue() instanceof Map) {
section.createSection(entry.getKey().toString(), (Map<?, ?>) entry.getValue());
} else {
section.set(entry.getKey().toString(), entry.getValue());
}
}
return section;
}
// Primitives
public String getString(String path) {
Object def = getDefault(path);
return getString(path, def != null ? def.toString() : null);
}
public String getString(String path, String def) {
Object val = get(path, def);
return (val != null) ? val.toString() : def;
}
public boolean isString(String path) {
Object val = get(path);
return val instanceof String;
}
public int getInt(String path) {
Object def = getDefault(path);
return getInt(path, (def instanceof Number) ? toInt(def) : 0);
}
public int getInt(String path, int def) {
Object val = get(path, def);
return (val instanceof Number) ? toInt(val) : def;
}
public boolean isInt(String path) {
Object val = get(path);
return val instanceof Integer;
}
public boolean getBoolean(String path) {
Object def = getDefault(path);
return getBoolean(path, (def instanceof Boolean) ? (Boolean) def : false);
}
public boolean getBoolean(String path, boolean def) {
Object val = get(path, def);
return (val instanceof Boolean) ? (Boolean) val : def;
}
public boolean isBoolean(String path) {
Object val = get(path);
return val instanceof Boolean;
}
public double getDouble(String path) {
Object def = getDefault(path);
return getDouble(path, (def instanceof Number) ? toDouble(def) : 0);
}
public double getDouble(String path, double def) {
Object val = get(path, def);
return (val instanceof Number) ? toDouble(val) : def;
}
public boolean isDouble(String path) {
Object val = get(path);
return val instanceof Double;
}
public long getLong(String path) {
Object def = getDefault(path);
return getLong(path, (def instanceof Number) ? toLong(def) : 0);
}
public long getLong(String path, long def) {
Object val = get(path, def);
return (val instanceof Number) ? toLong(val) : def;
}
public boolean isLong(String path) {
Object val = get(path);
return val instanceof Long;
}
// Java
public List<?> getList(String path) {
Object def = getDefault(path);
return getList(path, (def instanceof List) ? (List<?>) def : null);
}
public List<?> getList(String path, List<?> def) {
Object val = get(path, def);
return (List<?>) ((val instanceof List) ? val : def);
}
public boolean isList(String path) {
Object val = get(path);
return val instanceof List;
}
public List<String> getStringList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<String>(0);
}
List<String> result = new ArrayList<String>();
for (Object object : list) {
if ((object instanceof String) || (isPrimitiveWrapper(object))) {
result.add(String.valueOf(object));
}
}
return result;
}
public List<Integer> getIntegerList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Integer>(0);
}
List<Integer> result = new ArrayList<Integer>();
for (Object object : list) {
if (object instanceof Integer) {
result.add((Integer) object);
} else if (object instanceof String) {
try {
result.add(Integer.valueOf((String) object));
} catch (Exception ex) {
}
} else if (object instanceof Character) {
result.add((int) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).intValue());
}
}
return result;
}
public List<Boolean> getBooleanList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Boolean>(0);
}
List<Boolean> result = new ArrayList<Boolean>();
for (Object object : list) {
if (object instanceof Boolean) {
result.add((Boolean) object);
} else if (object instanceof String) {
if (Boolean.TRUE.toString().equals(object)) {
result.add(true);
} else if (Boolean.FALSE.toString().equals(object)) {
result.add(false);
}
}
}
return result;
}
public List<Double> getDoubleList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Double>(0);
}
List<Double> result = new ArrayList<Double>();
for (Object object : list) {
if (object instanceof Double) {
result.add((Double) object);
} else if (object instanceof String) {
try {
result.add(Double.valueOf((String) object));
} catch (Exception ex) {
}
} else if (object instanceof Character) {
result.add((double) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).doubleValue());
}
}
return result;
}
public List<Float> getFloatList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Float>(0);
}
List<Float> result = new ArrayList<Float>();
for (Object object : list) {
if (object instanceof Float) {
result.add((Float) object);
} else if (object instanceof String) {
try {
result.add(Float.valueOf((String) object));
} catch (Exception ex) {
}
} else if (object instanceof Character) {
result.add((float) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).floatValue());
}
}
return result;
}
public List<Long> getLongList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Long>(0);
}
List<Long> result = new ArrayList<Long>();
for (Object object : list) {
if (object instanceof Long) {
result.add((Long) object);
} else if (object instanceof String) {
try {
result.add(Long.valueOf((String) object));
} catch (Exception ex) {
}
} else if (object instanceof Character) {
result.add((long) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).longValue());
}
}
return result;
}
public List<Byte> getByteList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Byte>(0);
}
List<Byte> result = new ArrayList<Byte>();
for (Object object : list) {
if (object instanceof Byte) {
result.add((Byte) object);
} else if (object instanceof String) {
try {
result.add(Byte.valueOf((String) object));
} catch (Exception ex) {
}
} else if (object instanceof Character) {
result.add((byte) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).byteValue());
}
}
return result;
}
public List<Character> getCharacterList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Character>(0);
}
List<Character> result = new ArrayList<Character>();
for (Object object : list) {
if (object instanceof Character) {
result.add((Character) object);
} else if (object instanceof String) {
String str = (String) object;
if (str.length() == 1) {
result.add(str.charAt(0));
}
} else if (object instanceof Number) {
result.add((char) ((Number) object).intValue());
}
}
return result;
}
public List<Short> getShortList(String path) {
List<?> list = getList(path);
if (list == null) {
return new ArrayList<Short>(0);
}
List<Short> result = new ArrayList<Short>();
for (Object object : list) {
if (object instanceof Short) {
result.add((Short) object);
} else if (object instanceof String) {
try {
result.add(Short.valueOf((String) object));
} catch (Exception ex) {
}
} else if (object instanceof Character) {
result.add((short) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).shortValue());
}
}
return result;
}
public List<Map<?, ?>> getMapList(String path) {
List<?> list = getList(path);
List<Map<?, ?>> result = new ArrayList<Map<?, ?>>();
if (list == null) {
return result;
}
for (Object object : list) {
if (object instanceof Map) {
result.add((Map<?, ?>) object);
}
}
return result;
}
public ConfigurationSection getConfigurationSection(String path) {
Object val = get(path, null);
if (val != null) {
return (val instanceof ConfigurationSection) ? (ConfigurationSection) val : null;
}
val = get(path, getDefault(path));
return (val instanceof ConfigurationSection) ? createSection(path) : null;
}
public boolean isConfigurationSection(String path) {
Object val = get(path);
return val instanceof ConfigurationSection;
}
protected boolean isPrimitiveWrapper(Object input) {
return input instanceof Integer || input instanceof Boolean ||
input instanceof Character || input instanceof Byte ||
input instanceof Short || input instanceof Double ||
input instanceof Long || input instanceof Float;
}
protected Object getDefault(String path) {
if (path == null) throw new NullPointerException("Path may not be null");
Configuration root = getRoot();
Configuration defaults = root == null ? null : root.getDefaults();
return (defaults == null) ? null : defaults.get(createPath(this, path));
}
protected void mapChildrenKeys(Set<String> output, ConfigurationSection section, boolean deep) {
if (section instanceof MemorySection) {
MemorySection sec = (MemorySection) section;
for (Map.Entry<String, Object> entry : sec.map.entrySet()) {
output.add(createPath(section, entry.getKey(), this));
if ((deep) && (entry.getValue() instanceof ConfigurationSection)) {
ConfigurationSection subsection = (ConfigurationSection) entry.getValue();
mapChildrenKeys(output, subsection, deep);
}
}
} else {
Set<String> keys = section.getKeys(deep);
for (String key : keys) {
output.add(createPath(section, key, this));
}
}
}
protected void mapChildrenValues(Map<String, Object> output, ConfigurationSection section, boolean deep) {
if (section instanceof MemorySection) {
MemorySection sec = (MemorySection) section;
for (Map.Entry<String, Object> entry : sec.map.entrySet()) {
output.put(createPath(section, entry.getKey(), this), entry.getValue());
if (entry.getValue() instanceof ConfigurationSection) {
if (deep) {
mapChildrenValues(output, (ConfigurationSection) entry.getValue(), deep);
}
}
}
} else {
Map<String, Object> values = section.getValues(deep);
for (Map.Entry<String, Object> entry : values.entrySet()) {
output.put(createPath(section, entry.getKey(), this), entry.getValue());
}
}
}
/**
* Creates a full path to the given {@link ConfigurationSection} from its
* root {@link Configuration}.
* <p>
* You may use this method for any given {@link ConfigurationSection}, not
* only {@link MemorySection}.
*
* @param section Section to create a path for.
* @param key Name of the specified section.
* @return Full path of the section from its root.
*/
public static String createPath(ConfigurationSection section, String key) {
return createPath(section, key, (section == null) ? null : section.getRoot());
}
/**
* Creates a relative path to the given {@link ConfigurationSection} from
* the given relative section.
* <p>
* You may use this method for any given {@link ConfigurationSection}, not
* only {@link MemorySection}.
*
* @param section Section to create a path for.
* @param key Name of the specified section.
* @param relativeTo Section to create the path relative to.
* @return Full path of the section from its root.
*/
public static String createPath(ConfigurationSection section, String key, ConfigurationSection relativeTo) {
if (section == null) throw new NullPointerException("Cannot create path without a section");
Configuration root = section.getRoot();
if (root == null) {
throw new IllegalStateException("Cannot create path without a root");
}
char separator = root.options().pathSeparator();
StringBuilder builder = new StringBuilder();
if (section != null) {
for (ConfigurationSection parent = section; (parent != null) && (parent != relativeTo); parent = parent.getParent()) {
if (builder.length() > 0) {
builder.insert(0, separator);
}
builder.insert(0, parent.getName());
}
}
if ((key != null) && (key.length() > 0)) {
if (builder.length() > 0) {
builder.append(separator);
}
builder.append(key);
}
return builder.toString();
}
@Override
public String toString() {
Configuration root = getRoot();
return new StringBuilder()
.append(getClass().getSimpleName())
.append("[path='")
.append(getCurrentPath())
.append("', root='")
.append(root == null ? null : root.getClass().getSimpleName())
.append("']")
.toString();
}
}

View File

@ -0,0 +1,287 @@
package com.intellectualcrafters.configuration.file;
import com.intellectualcrafters.configuration.InvalidConfigurationException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import com.intellectualcrafters.configuration.Configuration;
import com.intellectualcrafters.configuration.MemoryConfiguration;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
/**
* This is a base class for all File based implementations of {@link
* Configuration}
*/
public abstract class FileConfiguration extends MemoryConfiguration {
/**
* This value specified that the system default encoding should be
* completely ignored, as it cannot handle the ASCII character set, or it
* is a strict-subset of UTF8 already (plain ASCII).
*
* @deprecated temporary compatibility measure
*/
@Deprecated
public static final boolean UTF8_OVERRIDE;
/**
* This value specifies if the system default encoding is unicode, but
* cannot parse standard ASCII.
*
* @deprecated temporary compatibility measure
*/
@Deprecated
public static final boolean UTF_BIG;
/**
* This value specifies if the system supports unicode.
*
* @deprecated temporary compatibility measure
*/
@Deprecated
public static final boolean SYSTEM_UTF;
static {
final byte[] testBytes = Base64Coder.decode("ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX4NCg==");
final String testString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\r\n";
final Charset defaultCharset = Charset.defaultCharset();
final String resultString = new String(testBytes, defaultCharset);
final boolean trueUTF = defaultCharset.name().contains("UTF");
UTF8_OVERRIDE = !testString.equals(resultString) || defaultCharset.equals(Charset.forName("US-ASCII"));
SYSTEM_UTF = trueUTF || UTF8_OVERRIDE;
UTF_BIG = trueUTF && UTF8_OVERRIDE;
}
/**
* Creates an empty {@link FileConfiguration} with no default values.
*/
public FileConfiguration() {
super();
}
/**
* Creates an empty {@link FileConfiguration} using the specified {@link
* Configuration} as a source for all default values.
*
* @param defaults Default value provider
*/
public FileConfiguration(Configuration defaults) {
super(defaults);
}
/**
* Saves this {@link FileConfiguration} to the specified location.
* <p>
* If the file does not exist, it will be created. If already exists, it
* will be overwritten. If it cannot be overwritten or created, an
* exception will be thrown.
* <p>
* This method will save using the system default encoding, or possibly
* using UTF8.
*
* @param file File to save to.
* @throws IOException Thrown when the given file cannot be written to for
* any reason.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void save(File file) throws IOException {
if (file == null) throw new NullPointerException("File cannot be null");
file.getParentFile().mkdirs();
String data = saveToString();
Writer writer = new OutputStreamWriter(new FileOutputStream(file), UTF8_OVERRIDE && !UTF_BIG ? StandardCharsets.UTF_8 : Charset.defaultCharset());
try {
writer.write(data);
} finally {
writer.close();
}
}
/**
* Saves this {@link FileConfiguration} to the specified location.
* <p>
* If the file does not exist, it will be created. If already exists, it
* will be overwritten. If it cannot be overwritten or created, an
* exception will be thrown.
* <p>
* This method will save using the system default encoding, or possibly
* using UTF8.
*
* @param file File to save to.
* @throws IOException Thrown when the given file cannot be written to for
* any reason.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void save(String file) throws IOException {
if (file == null) throw new NullPointerException("File cannot be null");
save(new File(file));
}
/**
* Saves this {@link FileConfiguration} to a string, and returns it.
*
* @return String containing this configuration.
*/
public abstract String saveToString();
/**
* Loads this {@link FileConfiguration} from the specified location.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given file.
* <p>
* If the file cannot be loaded for any reason, an exception will be
* thrown.
* <p>
* This will attempt to use the {@link Charset#defaultCharset()} for
* files, unless {@link #UTF8_OVERRIDE} but not {@link #UTF_BIG} is
* specified.
*
* @param file File to load from.
* @throws FileNotFoundException Thrown when the given file cannot be
* opened.
* @throws IOException Thrown when the given file cannot be read.
* @throws InvalidConfigurationException Thrown when the given file is not
* a valid Configuration.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void load(File file) throws FileNotFoundException, IOException, InvalidConfigurationException {
if (file == null) throw new NullPointerException("File cannot be null");
final FileInputStream stream = new FileInputStream(file);
load(new InputStreamReader(stream, UTF8_OVERRIDE && !UTF_BIG ? StandardCharsets.UTF_8 : Charset.defaultCharset()));
}
/**
* Loads this {@link FileConfiguration} from the specified stream.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given stream.
* <p>
* This will attempt to use the {@link Charset#defaultCharset()}, unless
* {@link #UTF8_OVERRIDE} or {@link #UTF_BIG} is specified.
*
* @param stream Stream to load from
* @throws IOException Thrown when the given file cannot be read.
* @throws InvalidConfigurationException Thrown when the given file is not
* a valid Configuration.
* @throws IllegalArgumentException Thrown when stream is null.
* @deprecated This does not consider encoding
* @see #load(Reader)
*/
@Deprecated
public void load(InputStream stream) throws IOException, InvalidConfigurationException {
if (stream == null) throw new NullPointerException("Stream cannot be null");
load(new InputStreamReader(stream, UTF8_OVERRIDE ? StandardCharsets.UTF_8 : Charset.defaultCharset()));
}
/**
* Loads this {@link FileConfiguration} from the specified reader.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given stream.
*
* @param reader the reader to load from
* @throws IOException thrown when underlying reader throws an IOException
* @throws InvalidConfigurationException thrown when the reader does not
* represent a valid Configuration
* @throws IllegalArgumentException thrown when reader is null
*/
public void load(Reader reader) throws IOException, InvalidConfigurationException {
BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
StringBuilder builder = new StringBuilder();
try {
String line;
while ((line = input.readLine()) != null) {
builder.append(line);
builder.append('\n');
}
} finally {
input.close();
}
loadFromString(builder.toString());
}
/**
* Loads this {@link FileConfiguration} from the specified location.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given file.
* <p>
* If the file cannot be loaded for any reason, an exception will be
* thrown.
*
* @param file File to load from.
* @throws FileNotFoundException Thrown when the given file cannot be
* opened.
* @throws IOException Thrown when the given file cannot be read.
* @throws InvalidConfigurationException Thrown when the given file is not
* a valid Configuration.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void load(String file) throws FileNotFoundException, IOException, InvalidConfigurationException {
if (file == null) throw new NullPointerException("File cannot be null");
load(new File(file));
}
/**
* Loads this {@link FileConfiguration} from the specified string, as
* opposed to from file.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given string.
* <p>
* If the string is invalid in any way, an exception will be thrown.
*
* @param contents Contents of a Configuration to load.
* @throws InvalidConfigurationException Thrown if the specified string is
* invalid.
* @throws IllegalArgumentException Thrown if contents is null.
*/
public abstract void loadFromString(String contents) throws InvalidConfigurationException;
/**
* Compiles the header for this {@link FileConfiguration} and returns the
* result.
* <p>
* This will use the header from {@link #options()} -> {@link
* FileConfigurationOptions#header()}, respecting the rules of {@link
* FileConfigurationOptions#copyHeader()} if set.
*
* @return Compiled header
*/
protected abstract String buildHeader();
@Override
public FileConfigurationOptions options() {
if (options == null) {
options = new FileConfigurationOptions(this);
}
return (FileConfigurationOptions) options;
}
}

View File

@ -0,0 +1,118 @@
package com.intellectualcrafters.configuration.file;
import com.intellectualcrafters.configuration.*;
/**
* Various settings for controlling the input and output of a {@link
* FileConfiguration}
*/
public class FileConfigurationOptions extends MemoryConfigurationOptions {
private String header = null;
private boolean copyHeader = true;
protected FileConfigurationOptions(MemoryConfiguration configuration) {
super(configuration);
}
@Override
public FileConfiguration configuration() {
return (FileConfiguration) super.configuration();
}
@Override
public FileConfigurationOptions copyDefaults(boolean value) {
super.copyDefaults(value);
return this;
}
@Override
public FileConfigurationOptions pathSeparator(char value) {
super.pathSeparator(value);
return this;
}
/**
* Gets the header that will be applied to the top of the saved output.
* <p>
* This header will be commented out and applied directly at the top of
* the generated output of the {@link FileConfiguration}. It is not
* required to include a newline at the end of the header as it will
* automatically be applied, but you may include one if you wish for extra
* spacing.
* <p>
* Null is a valid value which will indicate that no header is to be
* applied. The default value is null.
*
* @return Header
*/
public String header() {
return header;
}
/**
* Sets the header that will be applied to the top of the saved output.
* <p>
* This header will be commented out and applied directly at the top of
* the generated output of the {@link FileConfiguration}. It is not
* required to include a newline at the end of the header as it will
* automatically be applied, but you may include one if you wish for extra
* spacing.
* <p>
* Null is a valid value which will indicate that no header is to be
* applied.
*
* @param value New header
* @return This object, for chaining
*/
public FileConfigurationOptions header(String value) {
this.header = value;
return this;
}
/**
* Gets whether or not the header should be copied from a default source.
* <p>
* If this is true, if a default {@link FileConfiguration} is passed to
* {@link
* FileConfiguration#setDefaults(com.intellectualcrafters.configuration.Configuration)}
* then upon saving it will use the header from that config, instead of
* the one provided here.
* <p>
* If no default is set on the configuration, or the default is not of
* type FileConfiguration, or that config has no header ({@link #header()}
* returns null) then the header specified in this configuration will be
* used.
* <p>
* Defaults to true.
*
* @return Whether or not to copy the header
*/
public boolean copyHeader() {
return copyHeader;
}
/**
* Sets whether or not the header should be copied from a default source.
* <p>
* If this is true, if a default {@link FileConfiguration} is passed to
* {@link
* FileConfiguration#setDefaults(com.intellectualcrafters.configuration.Configuration)}
* then upon saving it will use the header from that config, instead of
* the one provided here.
* <p>
* If no default is set on the configuration, or the default is not of
* type FileConfiguration, or that config has no header ({@link #header()}
* returns null) then the header specified in this configuration will be
* used.
* <p>
* Defaults to true.
*
* @param value Whether or not to copy the header
* @return This object, for chaining
*/
public FileConfigurationOptions copyHeader(boolean value) {
copyHeader = value;
return this;
}
}

View File

@ -0,0 +1,254 @@
package com.intellectualcrafters.configuration.file;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Map;
import com.intellectualcrafters.configuration.Configuration;
import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.configuration.InvalidConfigurationException;
import com.intellectualcrafters.plot.PS;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.representer.Representer;
/**
* An implementation of {@link Configuration} which saves all files in Yaml.
* Note that this implementation is not synchronized.
*/
public class YamlConfiguration extends FileConfiguration {
protected static final String COMMENT_PREFIX = "# ";
protected static final String BLANK_CONFIG = "{}\n";
private final DumperOptions yamlOptions = new DumperOptions();
private final Representer yamlRepresenter = new YamlRepresenter();
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
@Override
public String saveToString() {
yamlOptions.setIndent(options().indent());
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yamlOptions.setAllowUnicode(SYSTEM_UTF);
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
String header = buildHeader();
String dump = yaml.dump(getValues(false));
if (dump.equals(BLANK_CONFIG)) {
dump = "";
}
return header + dump;
}
@Override
public void loadFromString(String contents) throws InvalidConfigurationException {
if (contents == null) throw new NullPointerException("Contents cannot be null");
Map<?, ?> input;
try {
input = (Map<?, ?>) yaml.load(contents);
} catch (YAMLException e) {
throw new InvalidConfigurationException(e);
} catch (ClassCastException e) {
throw new InvalidConfigurationException("Top level is not a Map.");
}
String header = parseHeader(contents);
if (header.length() > 0) {
options().header(header);
}
if (input != null) {
convertMapsToSections(input, this);
}
}
protected void convertMapsToSections(Map<?, ?> input, ConfigurationSection section) {
for (Map.Entry<?, ?> entry : input.entrySet()) {
String key = entry.getKey().toString();
Object value = entry.getValue();
if (value instanceof Map) {
convertMapsToSections((Map<?, ?>) value, section.createSection(key));
} else {
section.set(key, value);
}
}
}
protected String parseHeader(String input) {
String[] lines = input.split("\r?\n", -1);
StringBuilder result = new StringBuilder();
boolean readingHeader = true;
boolean foundHeader = false;
for (int i = 0; (i < lines.length) && (readingHeader); i++) {
String line = lines[i];
if (line.startsWith(COMMENT_PREFIX)) {
if (i > 0) {
result.append("\n");
}
if (line.length() > COMMENT_PREFIX.length()) {
result.append(line.substring(COMMENT_PREFIX.length()));
}
foundHeader = true;
} else if ((foundHeader) && (line.length() == 0)) {
result.append("\n");
} else if (foundHeader) {
readingHeader = false;
}
}
return result.toString();
}
@Override
protected String buildHeader() {
String header = options().header();
if (options().copyHeader()) {
Configuration def = getDefaults();
if ((def != null) && (def instanceof FileConfiguration)) {
FileConfiguration filedefaults = (FileConfiguration) def;
String defaultsHeader = filedefaults.buildHeader();
if ((defaultsHeader != null) && (defaultsHeader.length() > 0)) {
return defaultsHeader;
}
}
}
if (header == null) {
return "";
}
StringBuilder builder = new StringBuilder();
String[] lines = header.split("\r?\n", -1);
boolean startedHeader = false;
for (int i = lines.length - 1; i >= 0; i--) {
builder.insert(0, "\n");
if ((startedHeader) || (lines[i].length() != 0)) {
builder.insert(0, lines[i]);
builder.insert(0, COMMENT_PREFIX);
startedHeader = true;
}
}
return builder.toString();
}
@Override
public YamlConfigurationOptions options() {
if (options == null) {
options = new YamlConfigurationOptions(this);
}
return (YamlConfigurationOptions) options;
}
/**
* Creates a new {@link YamlConfiguration}, loading from the given file.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
* <p>
* The encoding used may follow the system dependent default.
*
* @param file Input file
* @return Resulting configuration
* @throws IllegalArgumentException Thrown if file is null
*/
public static YamlConfiguration loadConfiguration(File file) {
if (file == null) throw new NullPointerException("File cannot be null");
YamlConfiguration config = new YamlConfiguration();
try {
config.load(file);
} catch (FileNotFoundException ex) {
} catch (IOException ex) {
PS.log("Cannot load " + file);
ex.printStackTrace();
} catch (InvalidConfigurationException ex) {
PS.log("Cannot load " + file);
ex.printStackTrace();
}
return config;
}
/**
* Creates a new {@link YamlConfiguration}, loading from the given stream.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
*
* @param stream Input stream
* @return Resulting configuration
* @throws IllegalArgumentException Thrown if stream is null
* @deprecated does not properly consider encoding
* @see #load(InputStream)
* @see #loadConfiguration(Reader)
*/
@Deprecated
public static YamlConfiguration loadConfiguration(InputStream stream) {
if (stream == null) throw new NullPointerException("Stream cannot be null");
YamlConfiguration config = new YamlConfiguration();
try {
config.load(stream);
} catch (IOException ex) {
PS.log("Cannot load configuration from stream");
ex.printStackTrace();
} catch (InvalidConfigurationException ex) {
ex.printStackTrace();
PS.log("Cannot load configuration from stream");
}
return config;
}
/**
* Creates a new {@link YamlConfiguration}, loading from the given reader.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
*
* @param reader input
* @return resulting configuration
* @throws IllegalArgumentException Thrown if stream is null
*/
public static YamlConfiguration loadConfiguration(Reader reader) {
if (reader == null) throw new NullPointerException("Reader cannot be null");
YamlConfiguration config = new YamlConfiguration();
try {
config.load(reader);
} catch (IOException ex) {
PS.log("Cannot load configuration from stream");
ex.printStackTrace();
} catch (InvalidConfigurationException ex) {
PS.log("Cannot load configuration from stream");
ex.printStackTrace();
}
return config;
}
}

View File

@ -0,0 +1,69 @@
package com.intellectualcrafters.configuration.file;
/**
* Various settings for controlling the input and output of a {@link
* YamlConfiguration}
*/
public class YamlConfigurationOptions extends FileConfigurationOptions {
private int indent = 2;
protected YamlConfigurationOptions(YamlConfiguration configuration) {
super(configuration);
}
@Override
public YamlConfiguration configuration() {
return (YamlConfiguration) super.configuration();
}
@Override
public YamlConfigurationOptions copyDefaults(boolean value) {
super.copyDefaults(value);
return this;
}
@Override
public YamlConfigurationOptions pathSeparator(char value) {
super.pathSeparator(value);
return this;
}
@Override
public YamlConfigurationOptions header(String value) {
super.header(value);
return this;
}
@Override
public YamlConfigurationOptions copyHeader(boolean value) {
super.copyHeader(value);
return this;
}
/**
* Gets how much spaces should be used to indent each line.
* <p>
* The minimum value this may be is 2, and the maximum is 9.
*
* @return How much to indent by
*/
public int indent() {
return indent;
}
/**
* Sets how much spaces should be used to indent each line.
* <p>
* The minimum value this may be is 2, and the maximum is 9.
*
* @param value New indent
* @return This object, for chaining
*/
public YamlConfigurationOptions indent(int value) {
if (value < 2) throw new IllegalArgumentException("Indent must be at least 2 characters");
if (value > 9) throw new IllegalArgumentException("Indent cannot be greater than 9 characters");
this.indent = value;
return this;
}
}

View File

@ -0,0 +1,49 @@
package com.intellectualcrafters.configuration.file;
import java.util.LinkedHashMap;
import java.util.Map;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.nodes.Tag;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
public class YamlConstructor extends SafeConstructor {
public YamlConstructor() {
this.yamlConstructors.put(Tag.MAP, new ConstructCustomObject());
}
private class ConstructCustomObject extends ConstructYamlMap {
@Override
public Object construct(Node node) {
if (node.isTwoStepsConstruction()) {
throw new YAMLException("Unexpected referential mapping structure. Node: " + node);
}
Map<?, ?> raw = (Map<?, ?>) super.construct(node);
if (raw.containsKey(ConfigurationSerialization.SERIALIZED_TYPE_KEY)) {
Map<String, Object> typed = new LinkedHashMap<String, Object>(raw.size());
for (Map.Entry<?, ?> entry : raw.entrySet()) {
typed.put(entry.getKey().toString(), entry.getValue());
}
try {
return ConfigurationSerialization.deserializeObject(typed);
} catch (IllegalArgumentException ex) {
throw new YAMLException("Could not deserialize object", ex);
}
}
return raw;
}
@Override
public void construct2ndStep(Node node, Object object) {
throw new YAMLException("Unexpected referential mapping structure. Node: " + node);
}
}
}

View File

@ -0,0 +1,38 @@
package com.intellectualcrafters.configuration.file;
import java.util.LinkedHashMap;
import java.util.Map;
import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.representer.Representer;
public class YamlRepresenter extends Representer {
public YamlRepresenter() {
this.multiRepresenters.put(ConfigurationSection.class, new RepresentConfigurationSection());
this.multiRepresenters.put(ConfigurationSerializable.class, new RepresentConfigurationSerializable());
}
private class RepresentConfigurationSection extends RepresentMap {
@Override
public Node representData(Object data) {
return super.representData(((ConfigurationSection) data).getValues(false));
}
}
private class RepresentConfigurationSerializable extends RepresentMap {
@Override
public Node representData(Object data) {
ConfigurationSerializable serializable = (ConfigurationSerializable) data;
Map<String, Object> values = new LinkedHashMap<String, Object>();
values.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, ConfigurationSerialization.getAlias(serializable.getClass()));
values.putAll(serializable.serialize());
return super.representData(values);
}
}
}

View File

@ -0,0 +1,35 @@
package com.intellectualcrafters.configuration.serialization;
import java.util.Map;
/**
* Represents an object that may be serialized.
* <p>
* These objects MUST implement one of the following, in addition to the
* methods as defined by this interface:
* <ul>
* <li>A static method "deserialize" that accepts a single {@link Map}&lt;
* {@link String}, {@link Object}> and returns the class.</li>
* <li>A static method "valueOf" that accepts a single {@link Map}&lt;{@link
* String}, {@link Object}> and returns the class.</li>
* <li>A constructor that accepts a single {@link Map}&lt;{@link String},
* {@link Object}>.</li>
* </ul>
* In addition to implementing this interface, you must register the class
* with {@link ConfigurationSerialization#registerClass(Class)}.
*
* @see DelegateDeserialization
* @see SerializableAs
*/
public interface ConfigurationSerializable {
/**
* Creates a Map representation of this class.
* <p>
* This class must provide a method to restore this class, as defined in
* the {@link ConfigurationSerializable} interface javadocs.
*
* @return Map containing the current state of this class
*/
public Map<String, Object> serialize();
}

View File

@ -0,0 +1,266 @@
package com.intellectualcrafters.configuration.serialization;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.intellectualcrafters.configuration.Configuration;
/**
* Utility class for storing and retrieving classes for {@link Configuration}.
*/
public class ConfigurationSerialization {
public static final String SERIALIZED_TYPE_KEY = "==";
private final Class<? extends ConfigurationSerializable> clazz;
private static Map<String, Class<? extends ConfigurationSerializable>> aliases = new HashMap<String, Class<? extends ConfigurationSerializable>>();
protected ConfigurationSerialization(Class<? extends ConfigurationSerializable> clazz) {
this.clazz = clazz;
}
protected Method getMethod(String name, boolean isStatic) {
try {
Method method = clazz.getDeclaredMethod(name, Map.class);
if (!ConfigurationSerializable.class.isAssignableFrom(method.getReturnType())) {
return null;
}
if (Modifier.isStatic(method.getModifiers()) != isStatic) {
return null;
}
return method;
} catch (NoSuchMethodException ex) {
return null;
} catch (SecurityException ex) {
return null;
}
}
protected Constructor<? extends ConfigurationSerializable> getConstructor() {
try {
return clazz.getConstructor(Map.class);
} catch (NoSuchMethodException ex) {
return null;
} catch (SecurityException ex) {
return null;
}
}
protected ConfigurationSerializable deserializeViaMethod(Method method, Map<String, ?> args) {
try {
ConfigurationSerializable result = (ConfigurationSerializable) method.invoke(null, args);
if (result == null) {
Logger.getLogger(ConfigurationSerialization.class.getName()).log(Level.SEVERE, "Could not call method '" + method.toString() + "' of " + clazz + " for deserialization: method returned null");
} else {
return result;
}
} catch (Throwable ex) {
Logger.getLogger(ConfigurationSerialization.class.getName()).log(
Level.SEVERE,
"Could not call method '" + method.toString() + "' of " + clazz + " for deserialization",
ex instanceof InvocationTargetException ? ex.getCause() : ex);
}
return null;
}
protected ConfigurationSerializable deserializeViaCtor(Constructor<? extends ConfigurationSerializable> ctor, Map<String, ?> args) {
try {
return ctor.newInstance(args);
} catch (Throwable ex) {
Logger.getLogger(ConfigurationSerialization.class.getName()).log(
Level.SEVERE,
"Could not call constructor '" + ctor.toString() + "' of " + clazz + " for deserialization",
ex instanceof InvocationTargetException ? ex.getCause() : ex);
}
return null;
}
public ConfigurationSerializable deserialize(Map<String, ?> args) {
if (args == null) {
throw new NullPointerException("Args must not be null");
}
ConfigurationSerializable result = null;
Method method = null;
if (result == null) {
method = getMethod("deserialize", true);
if (method != null) {
result = deserializeViaMethod(method, args);
}
}
if (result == null) {
method = getMethod("valueOf", true);
if (method != null) {
result = deserializeViaMethod(method, args);
}
}
if (result == null) {
Constructor<? extends ConfigurationSerializable> constructor = getConstructor();
if (constructor != null) {
result = deserializeViaCtor(constructor, args);
}
}
return result;
}
/**
* Attempts to deserialize the given arguments into a new instance of the
* given class.
* <p>
* The class must implement {@link ConfigurationSerializable}, including
* the extra methods as specified in the javadoc of
* ConfigurationSerializable.
* <p>
* If a new instance could not be made, an example being the class not
* fully implementing the interface, null will be returned.
*
* @param args Arguments for deserialization
* @param clazz Class to deserialize into
* @return New instance of the specified class
*/
public static ConfigurationSerializable deserializeObject(Map<String, ?> args, Class<? extends ConfigurationSerializable> clazz) {
return new ConfigurationSerialization(clazz).deserialize(args);
}
/**
* Attempts to deserialize the given arguments into a new instance of the
* given class.
* <p>
* The class must implement {@link ConfigurationSerializable}, including
* the extra methods as specified in the javadoc of
* ConfigurationSerializable.
* <p>
* If a new instance could not be made, an example being the class not
* fully implementing the interface, null will be returned.
*
* @param args Arguments for deserialization
* @return New instance of the specified class
*/
public static ConfigurationSerializable deserializeObject(Map<String, ?> args) {
Class<? extends ConfigurationSerializable> clazz = null;
if (args.containsKey(SERIALIZED_TYPE_KEY)) {
try {
String alias = (String) args.get(SERIALIZED_TYPE_KEY);
if (alias == null) {
throw new IllegalArgumentException("Cannot have null alias");
}
clazz = getClassByAlias(alias);
if (clazz == null) {
throw new IllegalArgumentException("Specified class does not exist ('" + alias + "')");
}
} catch (ClassCastException ex) {
ex.fillInStackTrace();
throw ex;
}
} else {
throw new IllegalArgumentException("Args doesn't contain type key ('" + SERIALIZED_TYPE_KEY + "')");
}
return new ConfigurationSerialization(clazz).deserialize(args);
}
/**
* Registers the given {@link ConfigurationSerializable} class by its
* alias
*
* @param clazz Class to register
*/
public static void registerClass(Class<? extends ConfigurationSerializable> clazz) {
DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class);
if (delegate == null) {
registerClass(clazz, getAlias(clazz));
registerClass(clazz, clazz.getName());
}
}
/**
* Registers the given alias to the specified {@link
* ConfigurationSerializable} class
*
* @param clazz Class to register
* @param alias Alias to register as
* @see SerializableAs
*/
public static void registerClass(Class<? extends ConfigurationSerializable> clazz, String alias) {
aliases.put(alias, clazz);
}
/**
* Unregisters the specified alias to a {@link ConfigurationSerializable}
*
* @param alias Alias to unregister
*/
public static void unregisterClass(String alias) {
aliases.remove(alias);
}
/**
* Unregisters any aliases for the specified {@link
* ConfigurationSerializable} class
*
* @param clazz Class to unregister
*/
public static void unregisterClass(Class<? extends ConfigurationSerializable> clazz) {
while (aliases.values().remove(clazz)) {
;
}
}
/**
* Attempts to get a registered {@link ConfigurationSerializable} class by
* its alias
*
* @param alias Alias of the serializable
* @return Registered class, or null if not found
*/
public static Class<? extends ConfigurationSerializable> getClassByAlias(String alias) {
return aliases.get(alias);
}
/**
* Gets the correct alias for the given {@link ConfigurationSerializable}
* class
*
* @param clazz Class to get alias for
* @return Alias to use for the class
*/
public static String getAlias(Class<? extends ConfigurationSerializable> clazz) {
DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class);
if (delegate != null) {
if ((delegate.value() == null) || (delegate.value() == clazz)) {
delegate = null;
} else {
return getAlias(delegate.value());
}
}
if (delegate == null) {
SerializableAs alias = clazz.getAnnotation(SerializableAs.class);
if ((alias != null) && (alias.value() != null)) {
return alias.value();
}
}
return clazz.getName();
}
}

View File

@ -0,0 +1,22 @@
package com.intellectualcrafters.configuration.serialization;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Applies to a {@link ConfigurationSerializable} that will delegate all
* deserialization to another {@link ConfigurationSerializable}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DelegateDeserialization {
/**
* Which class should be used as a delegate for this classes
* deserialization
*
* @return Delegate class
*/
public Class<? extends ConfigurationSerializable> value();
}

View File

@ -0,0 +1,34 @@
package com.intellectualcrafters.configuration.serialization;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Represents an "alias" that a {@link ConfigurationSerializable} may be
* stored as.
* If this is not present on a {@link ConfigurationSerializable} class, it
* will use the fully qualified name of the class.
* <p>
* This value will be stored in the configuration so that the configuration
* deserialization can determine what type it is.
* <p>
* Using this annotation on any other class than a {@link
* ConfigurationSerializable} will have no effect.
*
* @see ConfigurationSerialization#registerClass(Class, String)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SerializableAs {
/**
* This is the name your class will be stored and retrieved as.
* <p>
* This name MUST be unique. We recommend using names such as
* "MyPluginThing" instead of "Thing".
*
* @return Name to serialize the class as.
*/
public String value();
}

View File

@ -16,7 +16,7 @@ import com.intellectualcrafters.plot.util.Logger.LogLevel;
import com.intellectualcrafters.plot.util.bukkit.UUIDHandler; import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import org.bukkit.configuration.file.YamlConfiguration; import com.intellectualcrafters.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -1084,7 +1084,7 @@ public class PS {
Settings.CONFIRM_UNLINK = config.getBoolean("confirmation.unlink"); Settings.CONFIRM_UNLINK = config.getBoolean("confirmation.unlink");
// Protection // Protection
Settings.REDSTONE_DISABLER = config.getBoolean("protection.tnt-listener.enabled"); Settings.REDSTONE_DISABLER = config.getBoolean("protection.redstone.disable-offline");
Settings.TNT_LISTENER = config.getBoolean("protection.tnt-listener.enabled"); Settings.TNT_LISTENER = config.getBoolean("protection.tnt-listener.enabled");
Settings.PISTON_FALLING_BLOCK_CHECK = config.getBoolean("protection.piston.falling-blocks"); Settings.PISTON_FALLING_BLOCK_CHECK = config.getBoolean("protection.piston.falling-blocks");

View File

@ -35,7 +35,7 @@ import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
import com.intellectualcrafters.plot.uuid.UUIDWrapper; import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration; import com.intellectualcrafters.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;

View File

@ -32,6 +32,7 @@ import com.intellectualcrafters.plot.object.PlotItemStack;
import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.BlockManager; import com.intellectualcrafters.plot.util.BlockManager;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.TaskManager;
public class MusicSubcommand extends SubCommand { public class MusicSubcommand extends SubCommand {
public MusicSubcommand() { public MusicSubcommand() {
@ -52,8 +53,19 @@ public class MusicSubcommand extends SubCommand {
PlotInventory inv = new PlotInventory(player, 2, "Plot Jukebox") { PlotInventory inv = new PlotInventory(player, 2, "Plot Jukebox") {
public boolean onClick(int index) { public boolean onClick(int index) {
PlotItemStack item = getItem(index); PlotItemStack item = getItem(index);
FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("music"), item.id)); int id = item.id == 7 ? 0 : item.id;
PlotListener.manager.plotEntry(player, plot); if (id == 0) {
FlagManager.removePlotFlag(plot, "music");
}
else {
FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("music"), id));
}
TaskManager.runTaskLater(new Runnable() {
@Override
public void run() {
PlotListener.manager.plotEntry(player, plot);
}
}, 1);
close(); close();
return false; return false;
} }
@ -66,6 +78,11 @@ public class MusicSubcommand extends SubCommand {
inv.setItem(index, item); inv.setItem(index, item);
index++; index++;
} }
if (player.getMeta("music") != null) {
String name = "&r&6Cancel music";
String[] lore = {"&r&cClick to cancel!"};
inv.setItem(index, new PlotItemStack(7, (short) 0, 1, name, lore));
}
inv.openInventory(); inv.openInventory();
return true; return true;
} }

View File

@ -28,8 +28,8 @@ import com.intellectualcrafters.plot.util.BlockManager;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.SetupUtils; import com.intellectualcrafters.plot.util.SetupUtils;
import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.TaskManager;
import org.bukkit.configuration.ConfigurationSection; import com.intellectualcrafters.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration; import com.intellectualcrafters.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;

View File

@ -127,12 +127,16 @@ public class Trim extends SubCommand {
plots.remove(0); plots.remove(0);
final Location pos1 = MainUtil.getPlotBottomLoc(world, plot.id); final Location pos1 = MainUtil.getPlotBottomLoc(world, plot.id);
final Location pos2 = MainUtil.getPlotTopLoc(world, plot.id); final Location pos2 = MainUtil.getPlotTopLoc(world, plot.id);
final Location pos3 = new Location(world, pos1.getX(), 64, pos2.getZ()); System.out.print(plot);
final Location pos4 = new Location(world, pos2.getX(), 64, pos1.getZ()); System.out.print(pos1);
chunks.remove(ChunkManager.getChunkChunk(pos1)); System.out.print(pos2);
chunks.remove(ChunkManager.getChunkChunk(pos2)); for (int x = pos1.getX(); x <= pos2.getX(); x += 512 ) {
chunks.remove(ChunkManager.getChunkChunk(pos3)); for (int z = pos1.getZ(); z <= pos2.getZ(); z += 512 ) {
chunks.remove(ChunkManager.getChunkChunk(pos4)); ChunkLoc chunk = ChunkManager.getChunkChunk(new Location(world, x, 0, z));
System.out.print(chunk.x + "," + chunk.z);
chunks.remove(chunk);
}
}
} }
} }
}, 20); }, 20);

View File

@ -22,6 +22,7 @@ package com.intellectualcrafters.plot.config;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import com.boydti.buildoff.config.BBC;
import com.intellectualsites.translation.TranslationFile; import com.intellectualsites.translation.TranslationFile;
import com.intellectualsites.translation.TranslationLanguage; import com.intellectualsites.translation.TranslationLanguage;
import com.intellectualsites.translation.TranslationManager; import com.intellectualsites.translation.TranslationManager;
@ -545,6 +546,20 @@ public enum C {
C(final String d, String cat) { C(final String d, String cat) {
this(d, true, cat.toLowerCase()); this(d, true, cat.toLowerCase());
} }
public static String format(C c, Object... args) {
String m = c.s;
for (int i = args.length - 1 ; i >= 0; i--) {
if (args[i] == null) {
continue;
}
m = m.replaceAll("%s" + i, args[i].toString());
}
if (args.length > 0) {
m = m.replaceAll("%s", args[0].toString());
}
return m;
}
public static void setupTranslations() { public static void setupTranslations() {
manager = new TranslationManager(); manager = new TranslationManager();

View File

@ -4,7 +4,7 @@ import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import org.bukkit.configuration.file.FileConfiguration; import com.intellectualcrafters.configuration.file.FileConfiguration;
import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.object.PlotId;

View File

@ -11,7 +11,7 @@ import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.bukkit.UUIDHandler; import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration; import com.intellectualcrafters.configuration.file.FileConfiguration;
import java.io.File; import java.io.File;
import java.sql.*; import java.sql.*;

View File

@ -30,8 +30,8 @@ import com.intellectualcrafters.plot.util.TaskManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
import org.bukkit.configuration.file.FileConfiguration; import com.intellectualcrafters.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import com.intellectualcrafters.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@ -1,7 +1,7 @@
package com.intellectualcrafters.plot.generator; package com.intellectualcrafters.plot.generator;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.configuration.ConfigurationSection; import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.Configuration; import com.intellectualcrafters.plot.config.Configuration;

View File

@ -25,7 +25,7 @@ import java.util.HashSet;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.configuration.ConfigurationSection; import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.C;

View File

@ -1,6 +1,6 @@
package com.intellectualcrafters.plot.generator; package com.intellectualcrafters.plot.generator;
import org.bukkit.configuration.ConfigurationSection; import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;

View File

@ -34,8 +34,10 @@ import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.object.comment.CommentManager; import com.intellectualcrafters.plot.object.comment.CommentManager;
import com.intellectualcrafters.plot.titles.AbstractTitle; import com.intellectualcrafters.plot.titles.AbstractTitle;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.bukkit.BukkitUtil; import com.intellectualcrafters.plot.util.bukkit.BukkitUtil;
import com.intellectualcrafters.plot.util.bukkit.UUIDHandler; import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -91,7 +93,7 @@ public class PlotListener extends APlotListener {
} }
public void plotEntry(final PlotPlayer pp, final Plot plot) { public void plotEntry(final PlotPlayer pp, final Plot plot) {
Player player = ((BukkitPlayer) pp).player; final Player player = ((BukkitPlayer) pp).player;
if (plot.hasOwner()) { if (plot.hasOwner()) {
final Flag gamemodeFlag = FlagManager.getPlotFlag(plot, "gamemode"); final Flag gamemodeFlag = FlagManager.getPlotFlag(plot, "gamemode");
if (gamemodeFlag != null) { if (gamemodeFlag != null) {
@ -137,18 +139,31 @@ public class PlotListener extends APlotListener {
} }
Flag musicFlag = FlagManager.getPlotFlag(plot, "music"); Flag musicFlag = FlagManager.getPlotFlag(plot, "music");
if (musicFlag != null) { if (musicFlag != null) {
player.playEffect(player.getLocation(), Effect.RECORD_PLAY, 0); final Integer id = (Integer) musicFlag.getValue();
Integer id = (Integer) musicFlag.getValue(); if ((id >= 2256 && id <= 2267) || id == 0) {
if (id >= 2256 && id <= 2267) { final org.bukkit.Location loc = player.getLocation();
Location center = MainUtil.getPlotCenter(plot); org.bukkit.Location lastLoc = (org.bukkit.Location) pp.getMeta("music");
org.bukkit.Location newLoc = BukkitUtil.getLocation(center); if (lastLoc != null) {
newLoc.setY(Math.min((player.getLocation().getBlockY() / 16) * 16, 240)); player.playEffect(lastLoc, Effect.RECORD_PLAY, 0);
if (id == 0) {
pp.deleteMeta("music");
return;
}
}
try { try {
player.playEffect(newLoc, Effect.RECORD_PLAY, Material.getMaterial(id)); pp.setMeta("music", loc);
player.playEffect(loc, Effect.RECORD_PLAY, Material.getMaterial(id));
} }
catch (Exception e) {} catch (Exception e) {}
} }
} }
else {
org.bukkit.Location lastLoc = (org.bukkit.Location) pp.getMeta("music");
if (lastLoc != null) {
pp.deleteMeta("music");
player.playEffect(lastLoc, Effect.RECORD_PLAY, 0);
}
}
CommentManager.sendTitle(pp, plot); CommentManager.sendTitle(pp, plot);
} }
} }
@ -169,13 +184,10 @@ public class PlotListener extends APlotListener {
if (FlagManager.getPlotFlag(plot, "weather") != null) { if (FlagManager.getPlotFlag(plot, "weather") != null) {
player.resetPlayerWeather(); player.resetPlayerWeather();
} }
if (FlagManager.getPlotFlag(plot, "music") != null) { org.bukkit.Location lastLoc = (org.bukkit.Location) pp.getMeta("music");
Location center = MainUtil.getPlotCenter(plot); if (lastLoc != null) {
for (int i = 0; i < 256; i+= 16) { pp.deleteMeta("music");
org.bukkit.Location newLoc = BukkitUtil.getLocation(center); player.playEffect(lastLoc, Effect.RECORD_PLAY, 0);
newLoc.setY(i);
player.playEffect(newLoc, Effect.RECORD_PLAY, 0);
}
} }
} }

View File

@ -199,7 +199,6 @@ public class PlotPlusListener extends PlotListener implements Listener {
@EventHandler @EventHandler
public void onPlotLeave(final PlayerLeavePlotEvent event) { public void onPlotLeave(final PlayerLeavePlotEvent event) {
final Player leaver = event.getPlayer(); final Player leaver = event.getPlayer();
leaver.playEffect(leaver.getLocation(), Effect.RECORD_PLAY, 0);
final Plot plot = event.getPlot(); final Plot plot = event.getPlot();
if (FlagManager.getPlotFlag(plot, "farewell") != null) { if (FlagManager.getPlotFlag(plot, "farewell") != null) {
event.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', C.PREFIX_FAREWELL.s().replaceAll("%id%", plot.id + "") + FlagManager.getPlotFlag(plot, "farewell").getValueString())); event.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', C.PREFIX_FAREWELL.s().replaceAll("%id%", plot.id + "") + FlagManager.getPlotFlag(plot, "farewell").getValueString()));

View File

@ -28,7 +28,7 @@ import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.flag.FlagManager; import com.intellectualcrafters.plot.flag.FlagManager;
import com.intellectualcrafters.plot.util.EconHandler; import com.intellectualcrafters.plot.util.EconHandler;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.configuration.ConfigurationSection; import com.intellectualcrafters.configuration.ConfigurationSection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;

View File

@ -42,8 +42,8 @@ import java.util.logging.Level;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException; import com.intellectualcrafters.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import com.intellectualcrafters.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;

View File

@ -24,8 +24,8 @@ import org.bukkit.Material;
import org.bukkit.Statistic; import org.bukkit.Statistic;
import org.bukkit.Statistic.Type; import org.bukkit.Statistic.Type;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization; import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;

View File

@ -4,7 +4,7 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;

View File

@ -8,8 +8,8 @@ import java.util.logging.Level;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization; import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableBiMap;

View File

@ -4,8 +4,8 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization; import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;

View File

@ -9,7 +9,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.bukkit.configuration.file.YamlConfiguration; import com.intellectualcrafters.configuration.file.YamlConfiguration;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;