package io.statik.report; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.Collection; import java.util.List; /** * Class for loading JSON configuration. * <p/> * Methods in this class should return null for invalid paths. */ public class Configuration { private final JSONObject configRoot; /** * Initializes this Configuration with the given configuration root object. * * @param configRoot The root of the configuration */ public Configuration(final JSONObject configRoot) { this.configRoot = configRoot; } /** * Initializes this Configuration with the given file's contents, which are validated. * * @param file File containing JSON */ public Configuration(final File file) { final List<String> lines; try { lines = Files.readAllLines(file.toPath(), Charset.forName("UTF-8")); } catch (final IOException ex) { throw new IllegalArgumentException("File could not be read: " + file.getAbsolutePath(), ex); } try { this.configRoot = new JSONObject(this.join(lines, '\n')); } catch (final JSONException ex) { throw new IllegalArgumentException("Given configuration file was invalid", ex); } } /** * Joins a collection of Strings by delimiter. * * @param strings Strings to join * @param delimiter Delimiter to place between the Strings * @return Joined String */ private String join(final Collection<String> strings, char delimiter) { return this.join(strings.toArray(new String[strings.size()]), delimiter, 0, strings.size()); } /** * Joins an array of Strings by delimiter, starting at start (inclusive) and ending at end (exclusive). * * @param strings Strings to join * @param delimiter Delimiter to place between the Strings * @param start Start index (inclusive) * @param end End index (exclusive) * @return Joined String */ private String join(final String[] strings, char delimiter, int start, int end) { if (start >= strings.length || end > strings.length || start < 0 || end < 0) { throw new IllegalArgumentException("Invalid indices: start(" + start + ") end(" + end + ")"); } final StringBuilder sb = new StringBuilder(); for (int i = start; i < end; i++) sb.append(strings[i]).append(delimiter); return sb.length() > 1 ? sb.substring(0, sb.length() - 1) : sb.toString(); } /** * Gets a boolean from the given path. * * @param path Path to get boolean from * @param def Default value to use if the path cannot be found * @return boolean */ public boolean getBoolean(final String path, final boolean def) { final JSONObject parent = this.getJSONObject(this.getParent(path)); return parent == null ? def : parent.optBoolean(this.getLastNode(path), def); } /** * Gets the root of this Configuration. * * @return Root JSONObject */ public JSONObject getConfigRoot() { return this.configRoot; } /** * Gets an integer from the given path. * * @param path Path to get integer from * @param def Default value to use if the path cannot be found * @return int */ public int getInt(final String path, final int def) { final JSONObject parent = this.getJSONObject(this.getParent(path)); return parent == null ? def : parent.optInt(this.getLastNode(path), def); } /** * Gets a JSONArray at the given path. * * @param path Path to get the JSONArray from * @return JSONArray */ public JSONArray getJSONArray(final String path) { final JSONObject jo = this.getJSONObject(this.getParent(path)); return jo == null ? null : jo.optJSONArray(this.getLastNode(path)); } /** * Gets a JSONObject at the given path. * * @param path Path to get JSONObject from * @return JSONObject */ public JSONObject getJSONObject(final String path) { if (path.equals("")) return this.configRoot; JSONObject buffer = this.configRoot; for (final String part : path.split("\\.")) { buffer = buffer.optJSONObject(part); if (buffer == null) return null; } return buffer; } /** * Gets the last node in a given path. * <p/> * An input of <code>config.database.hostname</code> would yield <code>hostname</code> as the output. * * @param path Path to get last node from * @return Last node */ public String getLastNode(final String path) { final String[] split = path.split("\\."); return split.length < 1 ? path : split[split.length - 1]; } /** * Gets the parent node of the given path. * <p/> * An input of <code>config.database.hostname</code> would yield <code>config.database</code> as the output. * * @param path Path to get the parent node from * @return Parent node */ public String getParent(final String path) { final String[] split = path.split("\\."); return split.length < 1 ? path : this.join(split, '.', 0, split.length - 1); } /** * Gets a String at the given path. * * @param path Path to get String from * @param def Default value to use if the path cannot be found * @return String */ public String getString(final String path, final String def) { final JSONObject parent = this.getJSONObject(this.getParent(path)); return parent == null ? def : parent.optString(this.getLastNode(path), def); } /** * Checks to see if a path exists in this Configuration. * * @param path Path to check * @return true if the path exists, false if otherwise */ public boolean pathExists(final String path) { try { final JSONObject parent = this.getJSONObject(this.getParent(path)); return parent != null && parent.has(this.getLastNode(path)); } catch (final JSONException | IllegalArgumentException ex) { return false; } } }