/*
* 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.lwc.LWC;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Updates config files with config vars that aren't already stored in the local
* config file (so the config file appears to always be up to date.)
*/
public class ConfigUpdater {
/**
* Config nodes NOT to update - this includes child nodes
*/
private static List<String> BLACKLIST = Arrays.asList(
"protections.blocks",
"master",
"groups",
"players",
"defaults"
);
/**
* The cache for the reference config files
*/
private final Map<String, Configuration> referenceConfigFileCache = new HashMap<String, Configuration>();
/**
* Load the reference config files in the local jar file. The key in the map is the
* file name
*
* @return
*/
private Map<String, Configuration> loadReferenceConfigFiles() throws IOException {
if (referenceConfigFileCache.size() > 0) {
return referenceConfigFileCache;
}
// Load our jar file
ZipFile jarFile = new ZipFile(URLDecoder.decode(LWC.getInstance().getPlugin().getFile().getPath(), "UTF-8"));
// Begin loading the files
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()) {
ZipEntry file = (ZipEntry) entries.nextElement();
String name = file.getName();
// We only want config dir
if (!name.startsWith("config/") || !name.endsWith(".yml")) {
continue;
}
// Get just the name
String realName = name.substring(name.indexOf('/') + 1);
// Insert it
Configuration configuration = new Configuration(null);
configuration.load(jarFile.getInputStream(file));
referenceConfigFileCache.put(realName, configuration);
}
return referenceConfigFileCache;
}
/**
* Run the updater against a configuration file
*/
public void update(Configuration configuration) {
try {
Map<String, Configuration> referenceFiles = loadReferenceConfigFiles();
// Check for the file in the reference
Configuration reference = referenceFiles.get(configuration.getFile().getName());
// Was it found?
if (reference == null) {
return;
}
// The found keys
List<String> currentKeys = getKeysDepth2(configuration);
List<String> referenceKeys = getKeysDepth2(reference);
boolean modified = false;
// Now go through and add any new keys
for (String key : referenceKeys) {
boolean contains = configuration.getProperty(key) != null;
if (!contains) {
configuration.setProperty(key, reference.getProperty(key));
modified = true;
}
}
// Look for any config values to remove
for (String key : currentKeys) {
boolean contains = reference.getProperty(key) != null;
if (!contains) {
configuration.removeProperty(key);
modified = true;
}
}
// Save the file if it was modified
if (modified) {
configuration.save();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Get all of the nodes in a configuration file up to 1 node down from the root
* <pre>
* root
* -> node
* -> node
* -> subnode
* -> subnode
* </pre>
* In this case, the subnodes are not returned (the root and nodes however, are)
*
* @param configuration
* @return
*/
private List<String> getKeysDepth2(Configuration configuration) {
List<String> keys = new ArrayList<String>();
// go through the root
for (String key : configuration.getKeys(null)) {
// Is it blacklisted?
if (BLACKLIST.contains(key)) {
continue;
}
keys.add(key);
// Add the subnodes
for (String subkey : configuration.getKeys(key)) {
String fullKey = key + "." + subkey;
// Is it blacklisted?
if (BLACKLIST.contains(fullKey)) {
continue;
}
// good good!
keys.add(fullKey);
}
}
return keys;
}
}