/* * Copyright 2011 Tyler Blair. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and contributors and should not be interpreted as representing official policies, * either expressed or implied, of anybody else. */ package com.griefcraft.util.config; import com.griefcraft.scripting.ModuleLoader; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.reader.UnicodeReader; import org.yaml.snakeyaml.representer.Representer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.HashMap; import java.util.Map; public class Configuration extends ConfigurationNode { private Yaml yaml; private File file; /** * List of loaded config files */ private static Map<String, Configuration> loaded = new HashMap<>(); /** * The config updater for config files */ private static final ConfigUpdater updater = new ConfigUpdater(); protected Configuration(File file) { super(new HashMap<String, Object>()); DumperOptions options = new DumperOptions(); options.setIndent(4); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); yaml = new Yaml(new SafeConstructor(), new Representer(), options); this.file = file; } /** * Gets the file * * @return */ public File getFile() { return file; } /** * Reload the configuration maps */ public static void reload() { for (Configuration configuration : loaded.values()) { configuration.load(configuration.file); } } /** * @return the list of loaded config files */ public static Map<String, Configuration> getLoaded() { return loaded; } /** * Create and/or load a configuration file * * @param config * @return */ public static Configuration load(String config) { return load(config, true); } /** * Create and/or load a configuration file * * @param config * @param extractConfig * @return */ public static Configuration load(String config, boolean extractConfig) { if (loaded.containsKey(config)) { return loaded.get(config); } File file = new File(ModuleLoader.ROOT_PATH + config); File folder = new File(ModuleLoader.ROOT_PATH); if (!folder.exists()) { folder.mkdir(); } // if it does not exist, attempt to download it if possible :-) if (!file.exists()) { if (!extractConfig) { return null; } extractFile("/config/" + config, ModuleLoader.ROOT_PATH + config); } Configuration configuration = new Configuration(file); configuration.load(file); loaded.put(config, configuration); // Run the config updater updater.update(configuration); return configuration; } /** * Extract a file (in the jar) to the destination folder * * @param path * @param destFolder */ private static void extractFile(String path, String destFolder) { InputStream is = null; OutputStream os = null; try { is = updater.getClass().getResourceAsStream(path); os = new FileOutputStream(destFolder); byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { } } if (os != null) { try { os.close(); } catch (IOException e) { } } } } /** * Loads the configuration file with the given input stream * * @param inputStream */ public void load(InputStream inputStream) { try { read(yaml.load(new UnicodeReader(inputStream))); } catch (ConfigurationException e) { root = new HashMap<String, Object>(); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { } } } /** * Loads the configuration file. All errors are thrown away. */ public void load(File file) { try { cache.clear(); load(new FileInputStream(file)); } catch (IOException e) { root = new HashMap<String, Object>(); } } /** * Saves the configuration to disk. All errors are clobbered. * * @return true if it was successful */ public boolean save() { FileOutputStream stream = null; File parent = file.getParentFile(); if (parent != null) { parent.mkdirs(); } try { stream = new FileOutputStream(file); yaml.dump(root, new OutputStreamWriter(stream, "UTF-8")); return true; } catch (IOException e) { } finally { try { if (stream != null) { stream.close(); } } catch (IOException e) { } } return false; } @SuppressWarnings("unchecked") private void read(Object input) throws ConfigurationException { try { if (null == input) { root = new HashMap<String, Object>(); } else { root = (Map<String, Object>) input; } } catch (ClassCastException e) { throw new ConfigurationException("Root document must be an key-value structure"); } } /** * This method returns an empty ConfigurationNode for using as a * default in methods that select a node from a node list. * * @return */ public static ConfigurationNode getEmptyNode() { return new ConfigurationNode(new HashMap<String, Object>()); } }