From a023de85aa08c8f2b8b2441c6b14064eabee2775 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sat, 2 Apr 2016 15:07:33 -0400 Subject: Began work on general configuration stuff. I'll leave this sit for a while, and come back to it after some thought --- BJC-Utils2/pom.xml | 5 + .../java/bjc/utils/configuration/ConfigFile.java | 147 +++++++++++++++++++++ .../bjc/utils/configuration/Configuration.java | 26 ++++ .../java/bjc/utils/configuration/Configurator.java | 44 ++++++ .../java/bjc/utils/configuration/FieldMarker.java | 25 ++++ .../java/bjc/utils/configuration/FieldType.java | 147 +++++++++++++++++++++ 6 files changed, 394 insertions(+) create mode 100644 BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/configuration/Configuration.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/configuration/Configurator.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/configuration/FieldMarker.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/configuration/FieldType.java (limited to 'BJC-Utils2') diff --git a/BJC-Utils2/pom.xml b/BJC-Utils2/pom.xml index dd6111f..1eb345b 100644 --- a/BJC-Utils2/pom.xml +++ b/BJC-Utils2/pom.xml @@ -40,5 +40,10 @@ commons-lang3 3.4 + + org.json + json + 20160212 + diff --git a/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java b/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java new file mode 100644 index 0000000..056f775 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java @@ -0,0 +1,147 @@ +package bjc.utils.configuration; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +import javax.lang.model.SourceVersion; + +/** + * A config file with support for categories, comments and other thins + * + * @author ben + * + */ +public class ConfigFile { + private static Map topLevelCategories; + + /** + * A category in a configuration file + * @author ben + * + */ + public static class ConfigCategory { + private Map children; + + /** + * Create a new config category + */ + public ConfigCategory() { + children = new HashMap<>(); + } + + public void addChild(String childName, ConfigCategory child) { + children.put(childName, child); + } + } + + /** + * Parse the values in a config file from a stream + * + * @param source + * The stream to parse values from + * @return A config file with values parsed from the stream + */ + public static ConfigFile parse(InputStream source) { + Scanner scn = new Scanner(source); + + ConfigFile returnedFile = new ConfigFile(); + + while (scn.hasNextLine()) { + String currentLine = scn.nextLine(); + + // Ignore blank lines + if (currentLine.equals("")) { + continue; + } + + String[] currentTokens = currentLine.split(" "); + + // Ignore lines that start with a comment marker + if (isCommentMarker(currentTokens[0])) { + continue; + } else if (SourceVersion.isName(currentTokens[0]) + && currentTokens[1].equals("{")) { + topLevelCategories.put(currentTokens[0], parseCategory(currentTokens[0], scn)); + } + } + + return returnedFile; + } + + private static ConfigCategory parseCategory(String categoryName, + Scanner inputSource) { + ConfigCategory category = new ConfigCategory(); + + String currentLine = inputSource.nextLine(); + + String[] tokens = currentLine.split("\\s+ "); + + // Parse contents of category + while (!tokens[0].equals("}")) { + // Ignore lines starting with comment marker + if (isCommentMarker(tokens[0])) { + continue; + } + + int initialCommandToken = 0; + + // Skip over blank tokens from lots of spacing + for (int i = 0; i < tokens.length; i++) { + String token = tokens[i]; + + if (token.equals("")) { + continue; + } else { + initialCommandToken = i; + break; + } + } + + String[] relevantTokens = Arrays.copyOfRange(tokens, + initialCommandToken, tokens.length); + + // Parse child subcategories + if (SourceVersion.isName(relevantTokens[0]) + && relevantTokens[1].equals("{")) { + parseCategory(relevantTokens[0], inputSource); + } else { + // Parse config fields + parseEntry(category, relevantTokens); + } + currentLine = inputSource.nextLine(); + + tokens = currentLine.split("\\s+ "); + } + + return category; + } + + private static void parseEntry(ConfigCategory category, + String[] entryParts) { + String entry = String.join("", entryParts); + + String[] expParts = entry.split("="); + + String[] expSpecifiers = expParts[0].split(":"); + + String expType = expSpecifiers[0]; + String expName = expSpecifiers[1]; + + switch (expType) { + + } + } + + private static boolean isCommentMarker(String token) { + switch (token) { + case "#": + case "//": + return true; + default: + return false; + } + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/configuration/Configuration.java b/BJC-Utils2/src/main/java/bjc/utils/configuration/Configuration.java new file mode 100644 index 0000000..7944c44 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/configuration/Configuration.java @@ -0,0 +1,26 @@ +package bjc.utils.configuration; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that marks a class as having a config file bound to it + * + * For this annotation to be valid to apply to the class, the class must + * meet two qualities + * + * 1. Have a public no-args constructor + * + * 2. Have one or more fields annoted with a {@link FieldMarker} annotation + * + * @author ben + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface Configuration { +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/configuration/Configurator.java b/BJC-Utils2/src/main/java/bjc/utils/configuration/Configurator.java new file mode 100644 index 0000000..e116dea --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/configuration/Configurator.java @@ -0,0 +1,44 @@ +package bjc.utils.configuration; + +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Bind the values in a prepared class to a config file + * + * @author ben + * + */ +public class Configurator { + /** + * Bind the values in a config file to the values in a class, + * substituting default values if none are appropriate + * + * @param + * The type of the object to bind + * @param clasz + * The class of the object to bind + * @param inputSource + * The source to get input from + * @return A instance of the provided class, with values filled in from + * a config file + */ + public static E readConfig(Class clasz, + InputStream inputSource) { + try { + Constructor noArgConstructor = clasz.getConstructor(); + + E backingStore = noArgConstructor.newInstance(); + + return backingStore; + } catch (NoSuchMethodException | SecurityException + | InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + + return null; + } + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/configuration/FieldMarker.java b/BJC-Utils2/src/main/java/bjc/utils/configuration/FieldMarker.java new file mode 100644 index 0000000..1d59fa3 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/configuration/FieldMarker.java @@ -0,0 +1,25 @@ +package bjc.utils.configuration; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to bind a field to a field in a config file + * + * @author ben + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface FieldMarker { + /** + * The type of config field being represented + * + * @return The type of config field being represented + */ + public FieldType value(); +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/configuration/FieldType.java b/BJC-Utils2/src/main/java/bjc/utils/configuration/FieldType.java new file mode 100644 index 0000000..a1545e5 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/configuration/FieldType.java @@ -0,0 +1,147 @@ +package bjc.utils.configuration; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Container interface for field type markers + * + * There can't be a String field type, so for fields of a single string, + * use FieldType itself + * + * @author ben + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface FieldType { + /** + * Marker to indicate a field as a single boolean flag + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Flag { + /** + * The default value of the flag + * + * @return The default value of the flag + */ + boolean value() default false; + } + + /** + * Marker to indicate a fields as an array of boolean flags + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Flags { + /** + * The default value of the flags + * + * @return The default value of the flags + */ + boolean[] value() default { false }; + } + + /** + * Marker to indicate a field as a single floating point value + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Float { + /** + * The default value of the number + * + * @return The default value of the number + */ + double value() default 0.0; + } + + /** + * Marker to indicate a fields as an array of floating point values + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Floats { + /** + * The default value of the numbers + * + * @return The default value of the numbers + */ + double[] value() default { 0.0 }; + } + + /** + * Marker to indicate a field as a single integral value + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Integer { + /** + * The default value of the integer + * + * @return The default value of the integer + */ + int value() default 0; + } + + /** + * Marker to indicate a fields as an array of integral values + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Integers { + /** + * The default value of the integers + * + * @return The default value of the integers + */ + int[] value() default { 0 }; + } + + /** + * Marker to indicate a fields as an array of strings + * + * @author Benjamin + * + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Strings { + /** + * The default value of each of the strings + * + * @return The default value of each of the strings + */ + String[] value() default { "" }; + } + + /** + * The default value of the string + * + * @return The default value of the strings + */ + public String value() default ""; +} -- cgit v1.2.3