summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/bukkit/configuration/file/YamlConfiguration.java')
-rw-r--r--src/main/java/org/bukkit/configuration/file/YamlConfiguration.java228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java b/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java
new file mode 100644
index 00000000..2ce6fcba
--- /dev/null
+++ b/src/main/java/org/bukkit/configuration/file/YamlConfiguration.java
@@ -0,0 +1,228 @@
+package org.bukkit.configuration.file;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.Configuration;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.ConfigurationSerialization;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * An implementation of {@link Configuration} which saves all files in Yaml.
+ */
+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 Representer();
+ private final Yaml yaml = new Yaml(new SafeConstructor(), yamlRepresenter, yamlOptions);
+
+ @Override
+ public String saveToString() {
+ Map<String, Object> output = new LinkedHashMap<String, Object>();
+
+ yamlOptions.setIndent(options().indent());
+ yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+
+ serializeValues(output, getValues(false));
+
+ String dump = yaml.dump(output);
+
+ if (dump.equals(BLANK_CONFIG)) {
+ dump = "";
+ }
+
+ return buildHeader() + dump;
+ }
+
+ @Override
+ public void loadFromString(String contents) throws InvalidConfigurationException {
+ if (contents == null) {
+ throw new IllegalArgumentException("Contents cannot be null");
+ }
+
+ Map<String, Object> input;
+ try {
+ input = (Map<String, Object>)yaml.load(contents);
+ } catch (Throwable ex) {
+ throw new InvalidConfigurationException("Specified contents is not a valid Configuration", ex);
+ }
+
+ deserializeValues(input, this);
+ }
+
+ protected void deserializeValues(Map<String, Object> input, ConfigurationSection section) throws InvalidConfigurationException {
+ if (input == null) {
+ return;
+ }
+
+ for (Map.Entry<String, Object> entry : input.entrySet()) {
+ Object value = entry.getValue();
+
+ if (value instanceof Map) {
+ Map<String, Object> subvalues;
+
+ try {
+ subvalues = (Map<String, Object>) value;
+ } catch (ClassCastException ex) {
+ throw new InvalidConfigurationException("Map found where type is not <String, Object>", ex);
+ }
+
+ if (subvalues.containsKey(ConfigurationSerialization.SERIALIZED_TYPE_KEY)) {
+ try {
+ ConfigurationSerializable serializable = ConfigurationSerialization.deserializeObject(subvalues);
+ section.set(entry.getKey(), serializable);
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidConfigurationException("Could not deserialize object", ex);
+ }
+ } else {
+ ConfigurationSection subsection = section.createSection(entry.getKey());
+ deserializeValues(subvalues, subsection);
+ }
+ } else {
+ section.set(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ protected void serializeValues(Map<String, Object> output, Map<String, Object> input) {
+ if (input == null) {
+ return;
+ }
+
+ for (Map.Entry<String, Object> entry : input.entrySet()) {
+ Object value = entry.getValue();
+
+ if (value instanceof ConfigurationSection) {
+ ConfigurationSection subsection = (ConfigurationSection)entry.getValue();
+ Map<String, Object> subvalues = new LinkedHashMap<String, Object>();
+
+ serializeValues(subvalues, subsection.getValues(false));
+ value = subvalues;
+ } else if (value instanceof ConfigurationSerializable) {
+ ConfigurationSerializable serializable = (ConfigurationSerializable)value;
+ Map<String, Object> subvalues = new LinkedHashMap<String, Object>();
+ subvalues.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, ConfigurationSerialization.getAlias(serializable.getClass()));
+
+ serializeValues(subvalues, serializable.serialize());
+ value = subvalues;
+ } else if ((!isPrimitiveWrapper(value)) && (!isNaturallyStorable(value))) {
+ throw new IllegalStateException("Configuration contains non-serializable values, cannot process");
+ }
+
+ if (value != null) {
+ output.put(entry.getKey(), value);
+ }
+ }
+ }
+
+ protected String buildHeader() {
+ String header = options().header();
+
+ if (header == null) {
+ return "";
+ }
+
+ StringBuilder builder = new StringBuilder();
+ String[] lines = header.split("\r?\n");
+
+ for (int i = 0; i < lines.length; i++) {
+ builder.append(COMMENT_PREFIX);
+ builder.append(lines[i]);
+ builder.append("\n");
+ }
+
+ 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.
+ *
+ * @param file Input file
+ * @return Resulting configuration
+ * @throws IllegalArgumentException Thrown is file is null
+ */
+ public static YamlConfiguration loadConfiguration(File file) {
+ if (file == null) {
+ throw new IllegalArgumentException("File cannot be null");
+ }
+
+ YamlConfiguration config = new YamlConfiguration();
+
+ try {
+ config.load(file);
+ } catch (FileNotFoundException ex) {
+ } catch (IOException ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file, ex);
+ } catch (InvalidConfigurationException ex) {
+ if (ex.getCause() instanceof YAMLException) {
+ Bukkit.getLogger().severe("Config file " + file + " isn't valid! " + ex.getCause());
+ } else if ((ex.getCause() == null) || (ex.getCause() instanceof ClassCastException)) {
+ Bukkit.getLogger().severe("Config file " + file + " isn't valid!");
+ } else {
+ Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file + ": " + ex.getCause().getClass(), ex);
+ }
+ }
+
+ 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 is stream is null
+ */
+ public static YamlConfiguration loadConfiguration(InputStream stream) {
+ if (stream == null) {
+ throw new IllegalArgumentException("Stream cannot be null");
+ }
+
+ YamlConfiguration config = new YamlConfiguration();
+
+ try {
+ config.load(stream);
+ } catch (IOException ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Cannot load configuration", ex);
+ } catch (InvalidConfigurationException ex) {
+ if (ex.getCause() instanceof YAMLException) {
+ Bukkit.getLogger().severe("Config file isn't valid! " + ex.getCause());
+ } else if ((ex.getCause() == null) || (ex.getCause() instanceof ClassCastException)) {
+ Bukkit.getLogger().severe("Config file isn't valid!");
+ } else {
+ Bukkit.getLogger().log(Level.SEVERE, "Cannot load configuration: " + ex.getCause().getClass(), ex);
+ }
+ }
+
+ return config;
+ }
+}