Parse cron strings as time duration specifications
authorGeorgios Gousios <gousiosg@gmail.com>
Mon, 24 Oct 2011 14:28:20 +0000 (17:28 +0300)
committerGeorgios Gousios <gousiosg@gmail.com>
Mon, 24 Oct 2011 14:28:20 +0000 (17:28 +0300)
logic/pom.xml
logic/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala
logic/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala

index 1717dd1..fc4d2e6 100644 (file)
       <name>SnakeYAML repository</name>
       <url>http://oss.sonatype.org/content/groups/public/</url>
     </repository>
+
+    <repository>
+      <id>java-crontab-syntax-parser-repo</id>
+      <name>Java CronTab Syntax Parser</name>
+      <url>
+        http://kenai.com/projects/crontab-parser/sources/maven-repo/content/
+      </url>
+    </repository>
   </repositories>
 
   <dependencies>
       <artifactId>snakeyaml</artifactId>
       <version>1.10-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>com.kenai.crontab-parser</groupId>
+      <artifactId>crontab-parser</artifactId>
+      <version>1.0.1</version>
+    </dependency>
   </dependencies>
 </project>
index bfe74ea..ab357be 100644 (file)
@@ -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)) }
   }
index f822352..8948f39 100644 (file)
@@ -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