com.googlecode.fascinator.common.JsonConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.fascinator.common.JsonConfig.java

Source

/* 
 * The Fascinator - Common Library
 * Copyright (C) 2008-2009 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.ByteArrayInputStream;
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.io.Writer;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Manages JSON configuration. Configuration values are read from a specified
 * JSON and if not found, the system-wide JSON will also be searched.
 * 
 * @author Oliver Lucido
 */
public class JsonConfig {

    /** Logging */
    private static Logger log = LoggerFactory.getLogger(JsonConfig.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";

    /** JSON system config */
    private JsonConfigHelper systemConfig;

    /** JSON user config */
    private JsonConfigHelper userConfig;

    /**
     * Creates a config with only the system settings
     * 
     * @throws IOException if these was an error parsing or reading the system
     *             JSON file
     */
    public JsonConfig() throws IOException {
        this((InputStream) null);
    }

    /**
     * Creates a JSON configuration from the specified file
     * 
     * @param jsonFile a JSON file
     * @throws IOException if there was an error parsing or reading the file
     */
    public JsonConfig(File jsonFile) throws IOException {
        this(new FileInputStream(jsonFile));
    }

    /**
     * Creates a JSON configuration from the specified input stream
     * 
     * @param jsonIn a JSON stream
     * @throws IOException if there was an error parsing or reading the stream
     */
    public JsonConfig(InputStream jsonIn) throws IOException {
        if (jsonIn == null) {
            userConfig = new JsonConfigHelper();
        } else {
            userConfig = new JsonConfigHelper(jsonIn);
        }
        systemConfig = new JsonConfigHelper(getSystemFile());
    }

    /**
     * Create a JSON configuration from the specified input string
     * 
     * @param jsonString
     * @throws IOException
     */
    public JsonConfig(String jsonString) throws IOException {
        this(new ByteArrayInputStream(jsonString.getBytes("UTF-8")));
    }

    /**
     * Gets the value of the specified node
     * 
     * @param path XPath to node
     * @return node value or null if not found
     */
    public String get(String path) {
        return get(path, null);
    }

    /**
     * Gets the value of the specified node, with a specified default if the not
     * was not found
     * 
     * @param path XPath to node
     * @param defaultValue value to return if the node was not found
     * @return node value or defaultValue if not found
     */
    public String get(String path, String defaultValue) {
        String value = userConfig.get(path);
        if (value == null) {
            value = systemConfig.get(path, defaultValue);
        }
        return value;
    }

    /**
     * Gets values of the specified node as a list. Use this method for JSON
     * arrays.
     * 
     * @param path XPath to node
     * @return value list, possibly empty
     */
    public List<Object> getList(String path) {
        List<Object> valueList = userConfig.getList(path);
        if (valueList.isEmpty()) {
            valueList = systemConfig.getList(path);
        }
        return valueList;
    }

    /**
     * Gets a map of the child nodes of the specified node
     * 
     * @param path XPath to node
     * @return node map, possibly empty
     */
    public Map<String, Object> getMap(String path) {
        Map<String, Object> valueMap = userConfig.getMap(path);
        if (valueMap.isEmpty()) {
            valueMap = systemConfig.getMap(path);
        }
        return valueMap;
    }

    /**
     * Gets a map of the child (and the 2nd level children) nodes of the
     * specified node
     * 
     * @param path XPath to node
     * @return node map, possibly empty
     */
    public Map<String, Object> getMapWithChild(String path) {
        Map<String, Object> valueMap = userConfig.getMapWithChild(path);
        if (valueMap.isEmpty()) {
            valueMap = systemConfig.getMapWithChild(path);
        }
        return valueMap;
    }

    /**
     * Sets the value of the specified node. If the node doesn't exist it is
     * created. The value can be set in the system configuration if necessary.
     * 
     * @param path XPath to node
     * @param value value to set
     * @param system set the value in the system configuration
     */
    public void set(String path, String value, boolean system) {
        if (system) {
            systemConfig.set(path, value);
        } else {
            userConfig.set(path, value);
        }
    }

    /**
     * Serialises the current state of the JSON configuration to the specified
     * writer. By default this doesn't use a pretty printer.
     * 
     * @param writer a writer
     * @throws IOException if there was an error writing the configuration
     */
    public void store(Writer writer) throws IOException {
        store(writer, false);
    }

    /**
     * Serialises the current state of the JSON configuration to the specified
     * writer. The output can be set to be pretty printed if required.
     * 
     * @param writer a writer
     * @param pretty use pretty printer
     * @throws IOException if there was an error writing the configuration
     */
    public void store(Writer writer, boolean pretty) throws IOException {
        userConfig.store(writer, pretty);
        FileWriter sysWriter = new FileWriter(getSystemFile());
        systemConfig.store(sysWriter, pretty);
        sysWriter.close();
    }

    /**
     * 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(JsonConfig.class.getResourceAsStream("/" + SYSTEM_CONFIG_FILE), out);
            out.close();
            log.info("Default configuration copied to '{}'", configFile);
        }
        return configFile;
    }

    /**
     * Gets the JSON Map of the specified node
     * 
     * @param path XPath to node
     * @return node map, possibly empty
     */
    public Map<String, JsonConfigHelper> getJsonMap(String path) {
        Map<String, JsonConfigHelper> value = userConfig.getJsonMap(path);
        if (value == null) {
            value = systemConfig.getJsonMap(path);
        }
        return value;
    }

    /**
     * 
     * @return The full JSON string
     */
    @Override
    public String toString() {
        return userConfig.toString();
    }

    /**
     * Tests whether or not the system-config has been properly configured.
     * 
     * @return <code>true</code> if configured, <code>false</code> if still
     *         using defaults
     */
    public boolean isConfigured() {
        return Boolean.parseBoolean(systemConfig.get("configured"));
    }

    /**
     * To check if configuration file is outdated
     * 
     * @return <code>true</code> if outdated, <code>false</code> otherwise
     */
    public boolean isOutdated() {
        boolean outdated = false;
        String systemVersion = systemConfig.get("version");
        try {
            JsonConfigHelper compiledConfig = new JsonConfigHelper(
                    getClass().getResourceAsStream("/" + SYSTEM_CONFIG_FILE));
            String compiledVersion = compiledConfig.get("version");
            outdated = !compiledVersion.equals(systemVersion);
            if (outdated) {
                log.debug("Configuration versions do not match! '{}' != '{}'", systemVersion, compiledVersion);
            }
        } catch (IOException ioe) {
            log.error("Failed to parse compiled configuration!", ioe);
        }
        return outdated;
    }
}