package org.royaldev.royalbot.configuration; import org.apache.commons.lang3.Validate; 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.nodes.Node; import org.yaml.snakeyaml.representer.Representer; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Map; /** * An implementation of {@link Configuration} which saves all files in Yaml. * Note that this implementation is not synchronized. */ public class YamlConfiguration extends FileConfiguration { private 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 SafeConstructor(), yamlRepresenter, yamlOptions); /** * 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 if file is null */ public static YamlConfiguration loadConfiguration(File file) { Validate.notNull(file, "File cannot be null"); YamlConfiguration config = new YamlConfiguration(); try { config.load(file); } catch (IOException ex) { ex.printStackTrace(); } return config; } public static YamlConfiguration loadConfiguration(InputStream is) { Validate.notNull(is, "InputStream cannot be null"); YamlConfiguration config = new YamlConfiguration(); try { config.load(is); } catch (IOException ex) { ex.printStackTrace(); } return config; } @Override public String saveToString() { yamlOptions.setIndent(2); yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); String dump = yaml.dump(getValues(false)); if (dump.equals(BLANK_CONFIG)) dump = ""; return dump; } @Override public void loadFromString(String contents) throws IOException { Validate.notNull(contents, "Contents cannot be null"); Map<?, ?> input; try { input = (Map<?, ?>) yaml.load(contents); } catch (YAMLException e) { throw new IOException(e); } catch (ClassCastException e) { throw new IOException("Top level is not a Map."); } 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); } } public class YamlRepresenter extends Representer { public YamlRepresenter() { this.multiRepresenters.put(ConfigurationSection.class, new RepresentConfigurationSection()); } private class RepresentConfigurationSection extends RepresentMap { @Override public Node representData(Object data) { return super.representData(((ConfigurationSection) data).getValues(false)); } } } }