From 42d2d82c74c7ea525300084a80207e08e5f135cc Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Thu, 15 Oct 2009 23:12:55 -0500 Subject: [PATCH] This version of the properties file uses it's own format. --- .../timestamper/core/TimelineProperties.java | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/jdbernard/timestamper/core/TimelineProperties.java diff --git a/src/jdbernard/timestamper/core/TimelineProperties.java b/src/jdbernard/timestamper/core/TimelineProperties.java new file mode 100644 index 0000000..d96aec8 --- /dev/null +++ b/src/jdbernard/timestamper/core/TimelineProperties.java @@ -0,0 +1,160 @@ +package jdbernard.timestamper.core; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.LinkedList; +import java.util.Scanner; +import java.util.StringTokenizer; + + +/** + * + * @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com}) + */ +public class TimelineProperties { + + private Timeline timeline; + private TimelineSource timelineSource; + private LinkedList syncTargets = new LinkedList(); + + public TimelineProperties(InputStream in) throws IOException { + parseConfig(in); + } + + private static enum ReadingState { + LocalTimelineDef, // expecting LOCAL TIMELINE definition + NewSync, // expecting a SYNC TO def + NewSyncOrOptions // either a NewDef, or a block of options + } + + private void parseConfig(InputStream is) throws IOException { + Scanner in = new Scanner(is); + URI sourceURI; + + // read the information for the local timeline + if (!nextExtendedToken(in, "LOCAL TIMELINE:")) { + throw new IOException("Missing 'LOCAL TIMELINE:' definition." + + " This must be the first line of the options file."); + } + + // parse the source URI + timelineSource = parseSource(in); + + // load timeline from source + timeline = timelineSource.read(); // TODO: authentication + + // add as many Syncs as we find + for (SyncTarget st = parseSync(in); st != null; st = parseSync(in)) + syncTargets.add(st); + } + + private SyncTarget parseSync(Scanner in) throws IOException { + SyncTarget st; + String token; + + if (!nextExtendedToken(in, "SYNC WITH:")) { return null; } + + st = new SyncTarget(parseSource(in), timeline); + + while (true) { + if (nextExtendedToken(in, "PULL ONLY")) { + st.enablePull(true); + st.enablePush(false); + } + + else if (nextExtendedToken(in, "PUSH ONLY")) { + st.enablePull(false); + st.enablePush(true); + } + + else if (nextExtendedToken(in, "PUSH AND PULL") || + nextExtendedToken(in, "PULL AND PUSH")) { + st.enablePull(true); + st.enablePush(true); + } + + else if (nextExtendedToken(in, "SYNC ON EXIT")) { + st.enableSyncOnExit(true); + } + + else if (nextExtendedToken(in, "UPDATE EVERY")) { + long updateAmount = 1; + + // parse the time amount if present + token = in.next("\\d+"); + if (token != null) { updateAmount = Long.parseLong(token); } + + token = in.next(); + if ("seconds".startsWith(token.toLowerCase())) + updateAmount *= 1000; + else if ("minutes".startsWith(token.toLowerCase())) + updateAmount *= 1000 * 60; + else if ("hours".startsWith(token.toLowerCase())) + updateAmount *= 1000 * 60 * 60; + else if ("days".startsWith(token.toLowerCase())) + updateAmount *= 1000 * 60 * 60 * 24; + else if ("weeks".startsWith(token.toLowerCase())) + updateAmount *= 1000 * 60 * 60 * 24 * 7; + else throw new IOException("'" + token + "' is not a supported" + + " measure of time. The supported measures are " + + "'seconds', 'minutes', 'hours', 'days', and 'weeks'."); + } + + else return st; + } + } + + private TimelineSource parseSource(Scanner in) throws IOException { + String strURI; + URI sourceURI; + + if (!in.hasNext()) { + throw new IOException("Expected the URI of a timeline source, but " + + "ran out of input."); + } + + strURI = in.next(); + try { sourceURI = new URI(strURI); } + catch (URISyntaxException urise) { + throw new IOException("The source link '" + strURI + "' is not a" + + " valid URI.", urise); + } + + return TimelineSourceFactory.newInstance(sourceURI); + } + + private static boolean nextExtendedToken(Scanner in, String expectedToken) + throws IOException { + StringTokenizer st = new StringTokenizer(expectedToken); + + if (st.countTokens() < 1 || !in.hasNext()) { return false; } + + // read one token + String curToken = st.nextToken(); + String inToken = in.next("(?i)\\Q" + curToken + "\\E"); + if (inToken == null) return false; + + while (st.hasMoreTokens()) { + curToken = st.nextToken(); + if (!in.hasNext()) { + throw new IOException("Ran out of input while expecting '" + + curToken + "' from '" + expectedToken + "'."); + } + + inToken = in.next("(?i)\\Q" + curToken + "\\E"); + if (inToken == null) { + throw new IOException("Found '" + in.next() + "' but expected '" + + curToken + "' from '" + expectedToken + "'."); + } + } + + return true; + } + + public void writeToStream(OutputStream out) throws IOException { + + } +}