From 6bbc59d595d7e92c712722648f98a21b6a62c882 Mon Sep 17 00:00:00 2001 From: Georgios Gousios Date: Mon, 24 Oct 2011 17:28:20 +0300 Subject: [PATCH] Parse cron strings as time duration specifications --- logic/pom.xml | 13 ++++ .../grnet/aquarium/logic/accounting/dsl/DSL.scala | 63 +++++++++++++++++++- .../gr/grnet/aquarium/logic/test/DSLTest.scala | 20 +++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/logic/pom.xml b/logic/pom.xml index 1717dd1..fc4d2e6 100644 --- a/logic/pom.xml +++ b/logic/pom.xml @@ -21,6 +21,14 @@ SnakeYAML repository http://oss.sonatype.org/content/groups/public/ + + + java-crontab-syntax-parser-repo + Java CronTab Syntax Parser + + http://kenai.com/projects/crontab-parser/sources/maven-repo/content/ + + @@ -52,5 +60,10 @@ snakeyaml 1.10-SNAPSHOT + + com.kenai.crontab-parser + crontab-parser + 1.0.1 + diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala index bfe74ea..ab357be 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala @@ -5,6 +5,8 @@ import java.io.InputStream import scala.collection.JavaConversions._ import org.slf4j.{LoggerFactory} import java.util.Date +import com.kenai.crontabparser.impl.CronTabParserBridge +import collection.mutable.Buffer class DSL @@ -43,7 +45,7 @@ object DSL { - val result = DSLPolicy("", "", Map(), DSLTimeFrame("", new Date(0), new Date(1), List())) + val result = DSLPolicy("", "", Map(), DSLTimeFrame(new Date(0), new Date(1), None)) val tmpresults = results ++ List(result) List(result) ++ parsePolicies(policies.tail, resources, tmpresults) } @@ -76,6 +78,65 @@ object DSL { mergeMaps(policy.algorithms, onto.algorithms), null) } + def parseTimeFrame(timeframe: Map[String,_]): DSLTimeFrame = { + val from = timeframe.getOrElse("from", throw new DSLParseException("No from field for timeframe")).asInstanceOf[Long] + + val to = timeframe.get("to") match { + case Some(x) => new Date(x.asInstanceOf[Long]) + case None => new Date(Long.MaxValue) + } + + val effective = timeframe.get("repeat") match { + case Some(x) => parseTimeFrameRepeat(x.asInstanceOf[Map[String,_]]) + case None => None + } + + DSLTimeFrame(new Date(from), to, Option(List())) + } + + def parseTimeFrameRepeat(tmr: Map[String,_]): List[DSLTimeFrameRepeat] = { + List(DSLTimeFrameRepeat(DSLCronSpec(0,0,0,0,0), DSLCronSpec(0,0,0,0,0))) + } + + def parseCronString(input: String): List[DSLCronSpec] = { + + if (input.split(" ").length != 5) + throw new DSLParseException("Only five-field cron strings allowed: " + input) + + if (input.contains(',')) + throw new DSLParseException("Multiple values per field are not allowed: " + input) + + val foo = try { + asScalaBuffer(CronTabParserBridge.parse(input)) + } catch { + case e => throw new DSLParseException("Error parsing cron string: " + e.getMessage) + } + + def splitMultiVals(input: String): Range = { + if (input.equals("*")) + return -1 until 0 + + if (input.contains('-')) { + val ints = input.split('-') + ints(0).toInt until ints(1).toInt + 1 + } else { + input.toInt until input.toInt + 1 + } + } + + splitMultiVals(foo.get(0).toString).map( + a => splitMultiVals(foo.get(1).toString).map( + b => splitMultiVals(foo.get(2).toString).map( + c => splitMultiVals(foo.get(3).toString).map( + d => splitMultiVals(foo.get(4).toString).map( + e => DSLCronSpec(a, b, c, d, e) + ) + ).flatten + ).flatten + ).flatten + ).flatten.toList + } + def mergeMaps[A, B](a: Map[A, B], b: Map[A, B]): Map[A, B] = { a ++ b.map{ case (k,v) => k -> (a.getOrElse(k,v)) } } diff --git a/logic/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala b/logic/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala index f822352..8948f39 100644 --- a/logic/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala +++ b/logic/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala @@ -31,4 +31,24 @@ class DSLTest { assertEquals(result.algorithms.get(bup), Some("def")) assertEquals(result.algorithms.get(bdown), Some("foo")) } + + @Test + def testCronParse = { + var input = "12 * * * *" + var output = DSL.parseCronString(input) + assertEquals(output, List(DSLCronSpec(12, -1, -1, -1, -1))) + + input = "12 4 3 jaN-ApR *" + output = DSL.parseCronString(input) + assertEquals(output.size, 4) + assertEquals(output(2), DSLCronSpec(12, 4, 3, 3, -1)) + + input = "12 4 foo jaN-ApR *" + try { + output = DSL.parseCronString(input) + assert(false) + } catch { + case e: Exception => assert(true) + } + } } \ No newline at end of file -- 1.7.10.4