
com.googlecode.fascinator.common.JsonSimpleConfig Maven / Gradle / Ivy
/*
* The Fascinator - JSON Simple Config
* Copyright (C) 2011 University of Southern Queensland
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package com.googlecode.fascinator.common;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.simple.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* An extension of the JsonSimple class specifically to access configuration.
*
*
*
* Aside from offering a constructor that takes care of finding and accessing
* the system configuration file, this class also offers a selection of methods
* for management of the system configuration, such as backup and version
* testing.
*
*
*
* Finally, whatever configuration is provided to this class, it will be backed
* by the full system configuration file. Nodes not found in the provided config
* will also be checked in the System config.
*
*
* @author Greg Pendlebury
*/
public class JsonSimpleConfig extends JsonSimple {
/** Logging */
private static Logger log = LoggerFactory.getLogger(JsonSimpleConfig.class);
/** Default configuration directory */
private static final String CONFIG_DIR = FascinatorHome.getPath();
/** Default system configuration file name */
private static final String SYSTEM_CONFIG_FILE = "system-config.json";
/** Fallback to system configuration file */
private JsonSimple systemConfig;
private static final String INCLUDE_DIR_KEY = "includeConfigDir";
private static final String INCLUDE_DIR_KEY_EXT = "includeConfigExt";
/**
* Creates JSON Configuration object from the system config file
*
* @throws IOException if there was an error during creation
*/
public JsonSimpleConfig() throws IOException {
super(JsonSimpleConfig.getSystemFile());
systemConfig = new JsonSimple(JsonSimpleConfig.getSystemFile());
loadIncludeDir();
}
/**
* Creates JSON Configuration object from the provided config file
*
* @param jsonFile : The file containing JSON
* @throws IOException if there was an error during creation
*/
public JsonSimpleConfig(File jsonFile) throws IOException {
super(jsonFile);
systemConfig = new JsonSimple(JsonSimpleConfig.getSystemFile());
loadIncludeDir();
}
/**
* Creates JSON Configuration object from the provided input stream
*
* @param jsonIn : The input stream to read
* @throws IOException if there was an error during creation
*/
public JsonSimpleConfig(InputStream jsonIn) throws IOException {
super(jsonIn);
systemConfig = new JsonSimple(JsonSimpleConfig.getSystemFile());
loadIncludeDir();
}
/**
* Creates JSON Configuration object from the provided config string
*
* @param jsonString : The JSON in string form
* @throws IOException if there was an error during creation
*/
public JsonSimpleConfig(String jsonString) throws IOException {
super(jsonString);
systemConfig = new JsonSimple(JsonSimpleConfig.getSystemFile());
loadIncludeDir();
}
/**
* Performs a backup on the system-wide configuration file from the default
* config dir if it exists. Returns a reference to the backed up file.
*
* @return the backed up system JSON file
* @throws IOException if there was an error reading or writing either file
*/
public static File backupSystemFile() throws IOException {
File configFile = new File(CONFIG_DIR, SYSTEM_CONFIG_FILE);
File backupFile = new File(CONFIG_DIR, SYSTEM_CONFIG_FILE + ".old");
if (!configFile.exists()) {
throw new IOException("System file does not exist! '"
+ configFile.getAbsolutePath() + "'");
} else {
if (backupFile.exists()) {
backupFile.delete();
}
OutputStream out = new FileOutputStream(backupFile);
InputStream in = new FileInputStream(configFile);
IOUtils.copy(in, out);
in.close();
out.close();
log.info("Configuration copied to '{}'", backupFile);
}
return backupFile;
}
/**
* Gets the system-wide configuration file from the default config dir. If
* the file doesn't exist, a default is copied to the config dir.
*
* @return the system JSON file
* @throws IOException if there was an error reading or writing the system
* configuration file
*/
public static File getSystemFile() throws IOException {
File configFile = new File(CONFIG_DIR, SYSTEM_CONFIG_FILE);
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
OutputStream out = new FileOutputStream(configFile);
IOUtils.copy(
JsonSimpleConfig.class.getResourceAsStream("/"
+ SYSTEM_CONFIG_FILE), out);
out.close();
log.info("Default configuration copied to '{}'", configFile);
}
return configFile;
}
/**
* Tests whether or not the system-config has been properly configured.
*
* @return true
if configured, false
if still
* using defaults
*/
public boolean isConfigured() {
return getBoolean(false, "configured");
}
/**
* To check if configuration file is outdated
*
* @return true
if outdated, false
otherwise
*/
public boolean isOutdated() {
boolean outdated = false;
String systemVersion = getString(null, "version");
if (systemVersion == null) {
return true;
}
try {
JsonSimple compiledConfig = new JsonSimple(getClass()
.getResourceAsStream("/" + SYSTEM_CONFIG_FILE));
String compiledVersion = compiledConfig.getString(null, "version");
outdated = !systemVersion.equals(compiledVersion);
if (compiledVersion == null) {
return false;
}
if (outdated) {
log.debug("Configuration versions do not match! '{}' != '{}'",
systemVersion, compiledVersion);
}
} catch (IOException ioe) {
log.error("Failed to parse compiled configuration!", ioe);
}
return outdated;
}
/**
* Walk down the JSON nodes specified by the path and retrieve the target
* JSONArray.
*
* @param path : Variable length array of path segments
* @return JSONArray : The target node, or NULL if path invalid or not an
* array
*/
@Override
public JSONArray getArray(Object... path) {
JSONArray array = super.getArray(path);
if (array == null && systemConfig != null) {
return systemConfig.getArray(path);
}
return array;
}
/**
* Walk down the JSON nodes specified by the path and retrieve the target
* JsonObject.
*
* @param path : Variable length array of path segments
* @return JsonObject : The target node, or NULL if path invalid or not an
* object
*/
@Override
public JsonObject getObject(Object... path) {
JsonObject object = super.getObject(path);
if (object == null && systemConfig != null) {
return systemConfig.getObject(path);
}
return object;
}
/**
* Walk down the JSON nodes specified by the path and retrieve the target.
*
* @param path : Variable length array of path segments
* @return Object : The target node, or NULL if invalid
*/
@Override
public Object getPath(Object... path) {
Object object = super.getPath(path);
if (object == null && systemConfig != null) {
return systemConfig.getPath(path);
}
return object;
}
/**
* Retrieve the Boolean value on the given path.
*
* IMPORTANT: The default value only applies if the path is
* not found. If a string on the path is found it will be considered
* false unless the value is 'true' (ignoring case). This is the
* default behaviour of the Boolean.parseBoolean() method.
*
* @param defaultValue : The fallback value to use if the path is invalid or
* not found
* @param path : An array of indeterminate length to use as the path
* @return Boolean : The Boolean value found on the given path, or null if
* no default provided
*/
@Override
public Boolean getBoolean(Boolean defaultValue, Object... path) {
Boolean bool = super.getBoolean(null, path);
if (bool == null) {
if (systemConfig != null) {
return systemConfig.getBoolean(defaultValue, path);
}
return defaultValue;
}
return bool;
}
/**
* Retrieve the Integer value on the given path.
*
* @param defaultValue : The fallback value to use if the path is invalid or
* not found
* @param path : An array of indeterminate length to use as the path
* @return Integer : The Integer value found on the given path, or null if
* no default provided
*/
@Override
public Integer getInteger(Integer defaultValue, Object... path) {
Integer integer = super.getInteger(null, path);
if (integer == null) {
if (systemConfig != null) {
return systemConfig.getInteger(defaultValue, path);
}
return defaultValue;
}
return integer;
}
/**
* Retrieve the String value on the given path.
*
* @param defaultValue : The fallback value to use if the path is invalid or
* not found
* @param path : An array of indeterminate length to use as the path
* @return String : The String value found on the given path, or null if no
* default provided
*/
@Override
public String getString(String defaultValue, Object... path) {
String string = super.getString(null, path);
if (string == null) {
if (systemConfig != null) {
return systemConfig.getString(defaultValue, path);
}
return defaultValue;
}
return string;
}
/**
*
* Retrieve a list of Strings found on the given path. Note that this is a
* utility function, and not designed for data traversal. It will
* only retrieve Strings found on the provided node, and the node must be a
* JSONArray.
*
*
* @param path : An array of indeterminate length to use as the path
* @return List : A list of Strings, null if the node is not found
*/
@Override
public List getStringList(Object... path) {
List list = super.getStringList(path);
if (list == null && systemConfig != null) {
return systemConfig.getStringList(path);
}
return list;
}
/**
*
* Retrieve a list of JsonSimple objects found on the given path. Note that
* this is a utility function, and not designed for data traversal. It
* will only retrieve valid JsonObjects found on the provided node,
* and wrap them in JsonSimple objects.
*
*
*
* Other objects found on that path will be ignored, and if the path itself
* is not a JSONArray or not found, the function will return NULL.
*
*
* @param path : An array of indeterminate length to use as the path
* @return List : A list of JSONSimple objects, or null
*/
@Override
public List getJsonSimpleList(Object... path) {
List list = super.getJsonSimpleList(path);
if (list == null && systemConfig != null) {
return systemConfig.getJsonSimpleList(path);
}
return list;
}
/**
*
* Retrieve a map of JsonSimple objects found on the given path. Note that
* this is a utility function, and not designed for data traversal. It
* will only retrieve valid JsonObjects found on the provided node,
* and wrap them in JsonSimple objects.
*
*
*
* Other objects found on that path will be ignored, and if the path itself
* is not a JsonObject or not found, the function will return NULL.
*
*
* @param path : An array of indeterminate length to use as the path
* @return Map : A map of JSONSimple objects, or null
*/
@Override
public Map getJsonSimpleMap(Object... path) {
Map map = super.getJsonSimpleMap(path);
if (map == null && systemConfig != null) {
return systemConfig.getJsonSimpleMap(path);
}
return map;
}
/**
*
* Search through the JSON for any nodes (at any depth) matching the
* requested name and return them. The returned List will be of type Object
* and require type interrogation for detailed use, but will be implemented
* as a LinkedList to preserve order.
*
*
* @param node : The node name we are looking for
* @return List