summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java147
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/configuration/Configuration.java26
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/configuration/Configurator.java44
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/configuration/FieldMarker.java25
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/configuration/FieldType.java147
5 files changed, 389 insertions, 0 deletions
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<String, ConfigCategory> topLevelCategories;
+
+ /**
+ * A category in a configuration file
+ * @author ben
+ *
+ */
+ public static class ConfigCategory {
+ private Map<String, ConfigCategory> 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 <E>
+ * 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> E readConfig(Class<E> clasz,
+ InputStream inputSource) {
+ try {
+ Constructor<E> 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 "";
+}