Reorganize credit model and enhance the YAML nodes with path info
authorChristos KK Loverdos <loverdos@gmail.com>
Mon, 31 Oct 2011 13:41:06 +0000 (15:41 +0200)
committerChristos KK Loverdos <loverdos@gmail.com>
Mon, 31 Oct 2011 13:45:18 +0000 (15:45 +0200)
26 files changed:
logic/src/main/scala/gr/grnet/aquarium/logic/credits/dsl/CreditsDSL.scala
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditAmount.scala
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionHow.scala [new file with mode: 0644]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionPolicy.scala [new file with mode: 0644]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionType.scala [deleted file]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionWhen.scala [new file with mode: 0644]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolder.scala
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolderClass.scala [deleted file]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditOrigin.scala
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructure.scala [deleted file]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructureClass.scala [deleted file]
logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/package.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala
logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala
logic/src/test/resources/credit-distribution-policies.yaml [new file with mode: 0644]
logic/src/test/resources/credit-distribution-types.yaml [deleted file]
logic/src/test/resources/credit-group-lab.yaml [new file with mode: 0644]
logic/src/test/resources/credit-holder-protos.yaml [deleted file]
logic/src/test/resources/credit-structure-greek-uni.yaml [deleted file]
logic/src/test/scala/gr/grnet/aquarium/logic/test/CreditDSLTest.scala

index a3d827f..7accffe 100644 (file)
@@ -1,9 +1,6 @@
 package gr.grnet.aquarium.logic.credits.dsl
 
-import gr.grnet.aquarium.util.yaml.YAMLHelpers
 import gr.grnet.aquarium.util.Loggable
-import gr.grnet.aquarium.logic.credits.model.{CreditStructureClass, CreditStructure}
-import java.io.{StringReader, InputStreamReader, Reader, InputStream}
 
 /**
  *
@@ -11,36 +8,5 @@ import java.io.{StringReader, InputStreamReader, Reader, InputStream}
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
 object CreditsDSL extends Loggable {
-  object Keys {
-    val StructureClass = "structure_class"
-    val Id = "id"
-    val Name = "name"
-    val Units = "units"
-    val Grouping = "grouping"
-  }
 
-  def parseString(s: CharSequence): CreditStructureClass = {
-    doParse(new StringReader(s.toString))
-  }
-
-  def parseStream(in: InputStream, encoding: String = "UTF-8", closeIn: Boolean = true): CreditStructureClass = {
-    doParse(new InputStreamReader(in, encoding), closeIn)
-  }
-
-  // FIXME: implement
-  private def doParse(r: Reader, closeReader: Boolean = true): CreditStructureClass = {
-    val creditsDocument = YAMLHelpers.loadYAML(r, closeReader)
-
-    val ystructureDef = creditsDocument / Keys.StructureClass
-    val yId = ystructureDef / Keys.Id
-    val yname  = ystructureDef / Keys.Name
-    val yunits = ystructureDef / Keys.Units
-    val ygrouping = ystructureDef / Keys.Grouping
-
-    logger.debug("name = %s".format(yname))
-    logger.debug("units = %s".format(yunits))
-    logger.debug("grouping = %s".format(ygrouping))
-
-    CreditStructureClass("", "", Nil)
-  }
 }
\ No newline at end of file
index 84bb122..66206da 100644 (file)
@@ -7,4 +7,4 @@ package gr.grnet.aquarium.logic.credits.model
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
-case class CreditAmount(amount: Long, creditOrigin: CreditOrigin)
\ No newline at end of file
+case class CreditAmount(amount: Long, origin: CreditOrigin)
\ No newline at end of file
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionHow.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionHow.scala
new file mode 100644 (file)
index 0000000..7a50e26
--- /dev/null
@@ -0,0 +1,46 @@
+package gr.grnet.aquarium.logic.credits.model
+
+/**
+ * 
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+sealed trait CreditDistributionHow {
+  def name: String
+  def attributes: Map[String, String]
+}
+
+object CreditDistributionHow {
+  object Names {
+    val CreditDistributionHowFixedAny = "CreditDistributionHowFixedAny"
+    val CreditDistributionHowFixedEqual = "CreditDistributionHowFixedEqual"
+    val CreditDistributionHowOnDemandUnlimited = "CreditDistributionHowOnDemandUnlimited"
+    val CreditDistributionHowOnDemandMax = "CreditDistributionHowOnDemandMax"
+    val CreditDistributionHowAlgorithmic = "CreditDistributionHowAlgorithmic"
+
+  }
+}
+
+case object CreditDistributionHowFixedAny extends CreditDistributionHow {
+  def name = CreditDistributionHow.Names.CreditDistributionHowFixedAny
+  def attributes = Map()
+}
+
+case object CreditDistributionHowFixedEqual extends CreditDistributionHow {
+  def name = CreditDistributionHow.Names.CreditDistributionHowFixedEqual
+  def attributes = Map()
+}
+
+case object CreditDistributionHowOnDemandUnlimited extends CreditDistributionHow {
+  def name = CreditDistributionHow.Names.CreditDistributionHowOnDemandUnlimited
+  def attributes = Map()
+}
+
+case class CreditDistributionHowOnDemandMax(max: Long) extends CreditDistributionHow {
+  def name = CreditDistributionHow.Names.CreditDistributionHowOnDemandMax
+  def attributes = Map("max" -> max.toString)
+}
+
+case class CreditDistributionHowAlgorithmic(algorithm: String) extends CreditDistributionHow {
+  def name = CreditDistributionHow.Names.CreditDistributionHowAlgorithmic
+  def attributes = Map("algorithm" -> algorithm)
+}
\ No newline at end of file
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionPolicy.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionPolicy.scala
new file mode 100644 (file)
index 0000000..8033fa7
--- /dev/null
@@ -0,0 +1,7 @@
+package gr.grnet.aquarium.logic.credits.model
+
+/**
+ * 
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+case class CreditDistributionPolicy(when: CreditDistributionWhen, how: CreditDistributionHow)
\ No newline at end of file
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionType.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionType.scala
deleted file mode 100644 (file)
index f9ce387..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-package gr.grnet.aquarium.logic.credits.model
-
-/**
- * The credit distribution type representation.
- *
- * This dictates how credits are distributed at lower level structure parts, for example
- * how a University distributes credits to its Departments.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-sealed trait CreditDistributionType {
-  def name: String
-  def value: Int
-
-  def isUnknown = false
-  def isFixed = isFixedAny || isFixedEqual
-  def isFixedAny = false
-  def isFixedEqual = false
-  def isOnDemandUnlimited = false
-  def isOnDemandMax = false
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-sealed abstract class CreditDistributionTypeSkeleton(_name: String,  _value: Int) extends CreditDistributionType {
-  def name = _name
-  def value = _value
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case object FixedAnyCreditDistributionType
-  extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.FixedAny, CreditDistributionType.Values.FixedEqual) {
-
-  override def isFixedAny = true
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case object FixedEqualCreditDistributionType
-  extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.FixedAny, CreditDistributionType.Values.FixedEqual) {
-
-  override def isFixedEqual = true
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case object OnDemandUnlimitedCreditDistributionType
-  extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.OnDemandUnlimited, CreditDistributionType.Values.OnDemandUnlimited) {
-
-  override def isOnDemandUnlimited = true
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case object OnDemandMaxCreditDistributionType
-  extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.OnDemandMax, CreditDistributionType.Values.OnDemandMax) {
-
-  override def isOnDemandMax = true
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class UnknownCreditDistributionType(reason: Option[String]) extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.Unknown, CreditDistributionType.Values.Unknown) {
-  override def isUnknown = true
-}
-
-object CreditDistributionType {
-  object Values {
-    /**
-     * Credits are distributed (pushed) in fixed values and parts can be divided at will.
-     */
-    val FixedAny = 10
-
-    /**
-     * Credits are distributed (pushed) in fixed values and parts are divided equally.
-     */
-    val FixedEqual = 20
-
-    /**
-     * Credits are distributed (pulled) on demand.
-     */
-    val OnDemandUnlimited = 30
-
-    /**
-     * Credits are distributed (pulled) on demand but up to a maximum value.
-     */
-    val OnDemandMax = 40
-
-    /**
-     * Error indicator
-     */
-    val Unknown = -1
-  }
-
-  object Names {
-    val FixedAny = "FixedAny"
-    val FixedEqual = "FixedEqual"
-    val OnDemandUnlimited = "OnDemandUnlimited"
-    val OnDemandMax = "OnDemandMax"
-    val Unknown = "Unknown"
-
-    val FixedAny_Lower = FixedAny.toLowerCase
-    val FixedEqual_Lower = FixedEqual.toLowerCase
-    val OnDemandUnlimited_Lower = OnDemandUnlimited.toLowerCase
-    val OnDemandMax_Lower = OnDemandMax.toLowerCase
-    val Unknown_Lower = Unknown.toLowerCase
-  }
-
-  def fromValue(value: Int): CreditDistributionType = {
-    value match {
-      case Values.FixedAny          => FixedAnyCreditDistributionType
-      case Values.FixedEqual        => FixedEqualCreditDistributionType
-      case Values.OnDemandUnlimited => OnDemandUnlimitedCreditDistributionType
-      case Values.OnDemandMax       => OnDemandMaxCreditDistributionType
-      case Values.Unknown           => UnknownCreditDistributionType(None)
-      case value                    => UnknownCreditDistributionType(Some("Bad value %s".format(value)))
-    }
-  }
-
-  def fromName(name: String): CreditDistributionType = {
-    name match {
-      case Names.FixedAny          => FixedAnyCreditDistributionType
-      case Names.FixedEqual        => FixedEqualCreditDistributionType
-      case Names.OnDemandUnlimited => OnDemandUnlimitedCreditDistributionType
-      case Names.OnDemandMax       => OnDemandMaxCreditDistributionType
-      case Names.Unknown           => UnknownCreditDistributionType(None)
-      case value                   => UnknownCreditDistributionType(Some("Bad value %s".format(value)))
-    }
-  }
-
-  def fromNameIgnoreCase(name: String): CreditDistributionType = {
-    name match {
-      case null => UnknownCreditDistributionType(Some("null name"))
-      case _    => name.toLowerCase match {
-        case Names.FixedAny_Lower          => FixedAnyCreditDistributionType
-        case Names.FixedEqual_Lower        => FixedEqualCreditDistributionType
-        case Names.OnDemandUnlimited_Lower => OnDemandUnlimitedCreditDistributionType
-        case Names.OnDemandMax_Lower       => OnDemandMaxCreditDistributionType
-        case Names.Unknown_Lower           => UnknownCreditDistributionType(None)
-        case value                         => UnknownCreditDistributionType(Some("Bad value %s".format(value)))
-      }
-    }
-  }
-}
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionWhen.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionWhen.scala
new file mode 100644 (file)
index 0000000..9c85d7e
--- /dev/null
@@ -0,0 +1,33 @@
+package gr.grnet.aquarium.logic.credits.model
+
+/**
+ * 
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+sealed trait CreditDistributionWhen {
+  def name: String
+  def attributes: Map[String, String]
+}
+
+object CreditDistributionWhen {
+  object Names {
+    val CreditDistributionWhenManual = "CreditDistributionWhenManual"
+    val CreditDistributionWhenPeriodic = "CreditDistributionWhenPeriodic"
+    val CreditDistributionWhenOnCreditArrival = "CreditDistributionWhenOnCreditArrival"
+  }
+}
+
+case object CreditDistributionWhenManual extends CreditDistributionWhen {
+  def name = CreditDistributionWhen.Names.CreditDistributionWhenManual
+  def attributes = Map()
+}
+
+case class CreditDistributionWhenPeriodic(cronPeriod: String) extends CreditDistributionWhen {
+  def name = CreditDistributionWhen.Names.CreditDistributionWhenPeriodic
+  def attributes = Map("cronPeriod" -> cronPeriod)
+}
+
+case object CreditDistributionWhenOnCreditArrival extends CreditDistributionWhen {
+  def name = CreditDistributionWhen.Names.CreditDistributionWhenOnCreditArrival
+  def attributes = Map()
+}
\ No newline at end of file
index 2923c37..988dc16 100644 (file)
@@ -1,11 +1,32 @@
 package gr.grnet.aquarium.logic.credits.model
 
+import java.net.URI
+
+
 /**
  * A credit holder is the entity to which credits can be assigned.
  *
+ * This can be the wallet.
+ *
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
-case class CreditHolder(name: String, creditHolderClass: CreditHolderClass) {
-  def isSingleHolderClass    = creditHolderClass.isSingleHolderClass
-  def isCompositeHolderClass = creditHolderClass.isCompositeHolderClass
-}
\ No newline at end of file
+sealed trait CreditHolder {
+  def name: String
+  def label: String
+  def isSingle: Boolean
+  def isGroup: Boolean
+  def members: List[String]
+  def wallet: List[CreditAmount]
+}
+
+case class UserCreditHolder(name: String, label: String, wallet: List[CreditAmount]) extends CreditHolder {
+  def isSingle = true
+  def isGroup = false
+  def members = Nil
+}
+
+case class GroupCreditHolder(name: String, label: String, members: List[String], wallet: List[CreditAmount]) extends CreditHolder {
+  def isSingle = false
+  def isGroup = true
+}
+
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolderClass.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolderClass.scala
deleted file mode 100644 (file)
index b657c0e..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-package gr.grnet.aquarium.logic.credits.model
-
-/**
- * A credit holder definition that is used to instantiate credit holders.
- *
- * Notice the OOP parlance resemblance.
-
- * Credit holders can be composite or not.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-sealed trait CreditHolderClass {
-  def name: String
-  def isSingleHolderClass: Boolean
-  def isCompositeHolderClass: Boolean
-  def members: List[CreditHolderClass]
-  def creditDistributions: MembersCreditDistributionMap
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class SingleCreditHolderClass(name: String) extends CreditHolderClass {
-  def members = Nil
-  def creditDistributions = Map()
-  def isSingleHolderClass = true
-  def isCompositeHolderClass = false
-}
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class CompositeCreditHolderClass(
-    name: String,
-    members: List[CreditHolderClass],
-    creditDistributions: MembersCreditDistributionMap)
-  extends CreditHolderClass {
-
-  def isSingleHolderClass = true
-  def isCompositeHolderClass = true
-}
\ No newline at end of file
index bf9d14d..9d864b8 100644 (file)
@@ -25,7 +25,7 @@ case object OwnCreditOrigin extends CreditOrigin {
   def name = CreditOrigin.Names.Own
 }
 
-case class InheritedCreditOrigin(creditHolder: CreditHolderClass, creditDistributionType: CreditDistributionType) extends CreditOrigin {
+case class InheritedCreditOrigin(creditHolder: CreditHolder, creditDistributionPolicy: CreditDistributionPolicy) extends CreditOrigin {
   override def isInherited = true
 
   def name = CreditOrigin.Names.Own
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructure.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructure.scala
deleted file mode 100644 (file)
index c1b0cb9..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package gr.grnet.aquarium.logic.credits.model
-
-/**
- * The actual credit structure instance for a particular client
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class CreditStructure(
-    id: String,
-    name: String,
-    creditStructureDef: CreditStructureClass,
-    members: List[CreditHolder])
\ No newline at end of file
diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructureClass.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructureClass.scala
deleted file mode 100644 (file)
index 17bec3e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package gr.grnet.aquarium.logic.credits.model
-
-/**
- * The definition of a credit structure.
- * This could mimic the organizational structure of the client though something like that is not necessary.
- *
- * These are top-level and system-wide definitions that can be reused.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class CreditStructureClass(
-    id: String,
-    name: String,
-    memberClasses: List[CreditHolderClass])
index 790bd30..026af8b 100644 (file)
@@ -5,5 +5,5 @@ package object model {
    * For a member of a structure, provide the credit distribution type
    * the parent follows for this member.
    */
-  type MembersCreditDistributionMap = Map[CreditHolderClass, List[CreditDistributionType]]
+  type MembersCreditDistributionMap = Map[CreditHolder, List[CreditDistributionPolicy]]
 }
\ No newline at end of file
index 24caa07..6b2c888 100644 (file)
@@ -4,10 +4,12 @@ package gr.grnet.aquarium.util.yaml
  * 
  * @author Georgios Gousios <gousiosg@gmail.com>.
  */
-case class YAMLDoubleNode(double: Double) extends YAMLNode {
+case class YAMLDoubleNode(path: String,  double: Double) extends YAMLNode {
   def /(childName: String) = YAMLEmptyNode
 
   override def doubleValue = double
 
   override def isDouble = true
+
+  def withPath(newPath: String) = this.copy(path = newPath)
 }
index 4b74e6b..0f5df19 100644 (file)
@@ -8,5 +8,8 @@ case object YAMLEmptyNode extends YAMLNode {
   def /(childName: String) = YAMLEmptyNode
 
   override def isEmpty = true
+
+  def path = ""
+  def withPath(newPath: String) = this
 }
 
index 5233a00..dfc2542 100644 (file)
@@ -4,10 +4,12 @@ package gr.grnet.aquarium.util.yaml
  * 
  * @author Georgios Gousios <gousiosg@gmail.com>.
  */
-case class YAMLIntNode(int: Int) extends YAMLNode {
+case class YAMLIntNode(path: String,  int: Int) extends YAMLNode {
   def /(childName: String) = YAMLEmptyNode
 
   override def intValue = int
-
   override def isInt = true
+
+
+  def withPath(newPath: String) = this.copy(path = newPath)
 }
index a77511f..557465e 100644 (file)
@@ -4,7 +4,7 @@ package gr.grnet.aquarium.util.yaml
  * 
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
-case class YAMLListNode(list: List[YAMLNode]) extends YAMLNode {
+case class YAMLListNode(path: String,  list: List[YAMLNode]) extends YAMLNode {
   def /(childName: String) = YAMLEmptyNode
 
   override def listValue = list
@@ -14,7 +14,15 @@ case class YAMLListNode(list: List[YAMLNode]) extends YAMLNode {
     case Nil    => YAMLEmptyNode
     case h :: _ => h
   }
-  def tail = YAMLListNode(list.tail)
+  def tail = YAMLListNode(path + "::tail", list.tail)
 
   override def isEmpty = list.isEmpty
+
+  override def foreach[T](f: (YAMLNode) => T) = {
+    for(node <- listValue) {
+      f(node)
+    }
+  }
+
+  def withPath(newPath: String) = this.copy(path = newPath)
 }
\ No newline at end of file
index f43c8b8..de915db 100644 (file)
@@ -6,12 +6,14 @@ import collection.mutable
  * 
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
-case class YAMLMapNode(map: mutable.Map[String, YAMLNode]) extends YAMLNode {
+case class YAMLMapNode(path: String, map: mutable.Map[String, YAMLNode]) extends YAMLNode {
   def /(childName: String) = map.get(childName) match {
-    case Some(child) => child
+    case Some(child) => child.withPath(YAMLNode.concatPaths(path, childName))
     case None => YAMLEmptyNode
   }
 
   override def mapValue = map.toMap // get an immutable version
   override def isMap = true
+
+  def withPath(newPath: String) = this.copy(path = newPath)
 }
index 78bb96e..b3ca950 100644 (file)
@@ -13,6 +13,11 @@ import scala.collection.JavaConversions._
 trait YAMLNode {
   def /(childName: String): YAMLNode
 
+  def name = path.substring(path.lastIndexOf('/') + 1)
+  
+  def path: String
+  def withPath(newPath: String): YAMLNode
+
   def intValue: Int = 0
   def doubleValue: Double = 0.0
   def stringValue: String = null
@@ -27,6 +32,8 @@ trait YAMLNode {
   def isMap = false
   def isList = false
   def isUnknown = false
+
+  def foreach[T](f: YAMLNode => T): Unit = {}
 }
 
 /**
@@ -35,37 +42,43 @@ trait YAMLNode {
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
 object YAMLNode {
-  def apply(obj: AnyRef): YAMLNode = {
+  def concatPaths(parent: String, child: String) = {
+    if(parent == "/") {
+      if(child startsWith "/") {
+        child
+      } else {
+        "/" + child
+      }
+    } else {
+      parent + "/" + child
+    }
+  }
+
+  def indexedPath(basePath: String, index: Int) = "%s[%s]".format(basePath, index)
+
+  def apply(obj: AnyRef, basePath: String = "/"): YAMLNode = {
     obj match {
       case null =>
         YAMLEmptyNode
-      case map: JMap[_, _] =>
-        val workingMap: mutable.Map[String, AnyRef] = map.asInstanceOf[JMap[String, AnyRef]]
-        val mappedMap = workingMap map {
+      case javaMap: JMap[_, _] =>
+        val scalaMap: mutable.Map[String, AnyRef] = javaMap.asInstanceOf[JMap[String, AnyRef]]
+        val nodeMap = scalaMap map {
           case (key, value) if value.isInstanceOf[YAMLNode] =>
-            (key, value).asInstanceOf[(String, YAMLNode)]
+            val yvalue = value.asInstanceOf[YAMLNode]//.withPath(concatPaths(basePath, key))
+            (key, yvalue)
           case (key, value) =>
-            (key, apply(value))
+            (key, apply(value, concatPaths(basePath, key)))
         }
-        YAMLMapNode(mappedMap)
-//      case map: mutable.Map[_, _] =>
-//        val workingMap = map
-//        val mappedMap = workingMap map {
-//          case (key, value) if value.isInstanceOf[YAMLNode] =>
-//            (key, value)
-//          case (key, value) =>
-//            (key, newYAMLNode(value))
-//        }
-//        YAMLMapNode(mappedMap)
-      case list: JList[_] =>
-        val workingList: mutable.Buffer[AnyRef] = list.asInstanceOf[JList[AnyRef]]
-        val mappedList = workingList.map(apply(_)).toList
-        YAMLListNode(mappedList)
+        YAMLMapNode(basePath, nodeMap)
+      case javaList: JList[_] =>
+        val scalaList: mutable.Buffer[AnyRef] = javaList.asInstanceOf[JList[AnyRef]]
+        val nodeList = scalaList.zipWithIndex.map { case (elem, index) => apply(elem, indexedPath(basePath, index)) }.toList
+        YAMLListNode(basePath, nodeList)
       case string: String =>
-        YAMLStringNode(string)
+        YAMLStringNode(basePath, string)
       case x: YAMLNode => x
       case int: java.lang.Integer =>
-        YAMLIntNode(int)
+        YAMLIntNode(basePath, int)
       case double: java.lang.Double =>
         YAMLDoubleNode(double)
       case obj =>
index c73c58e..23fceaf 100644 (file)
@@ -4,10 +4,12 @@ package gr.grnet.aquarium.util.yaml
  * 
  * @author Christos KK Loverdos <loverdos@gmail.com>.
  */
-case class YAMLStringNode(string: String) extends YAMLNode {
+case class YAMLStringNode(path: String,  string: String) extends YAMLNode {
   def /(childName: String) = YAMLEmptyNode
 
   override def stringValue = string
 
   override def isString = true
+
+  def withPath(newPath: String) = this.copy(path = newPath)
 }
index 8093709..c4d566c 100644 (file)
@@ -8,4 +8,7 @@ case class YAMLUnknownNode(unknownObj: AnyRef, actualType: String) extends YAMLN
   def /(childName: String) = this
 
   override def isUnknown = false
+
+  def path = ""
+  def withPath(newPath: String) = this
 }
diff --git a/logic/src/test/resources/credit-distribution-policies.yaml b/logic/src/test/resources/credit-distribution-policies.yaml
new file mode 100644 (file)
index 0000000..2e35463
--- /dev/null
@@ -0,0 +1,24 @@
+credit-distribution-policies:
+  - how:
+    - types:
+      - FixedAny
+      - FixedEqual
+      - OnDemandUnlimited
+      - OnDemandMax
+      - Algorithmic
+    - aliases: # aliases define named sets of credit distribution types
+      - AliasAny:
+        - FixedAny
+        - FixedEqual
+        - OnDemandUnlimited
+        - OnDemandMax
+      - AliasFixed:
+        - FixedAny
+        - FixedEqual
+      - AliasOnDemand:
+        - OnDemandUnlimited
+        - OnDemandMax
+  - when:
+    - OnCreditArrival
+    - Manual
+    - Periodic
\ No newline at end of file
diff --git a/logic/src/test/resources/credit-distribution-types.yaml b/logic/src/test/resources/credit-distribution-types.yaml
deleted file mode 100644 (file)
index 0d2ebe4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-credit-distribution:
-  - types:
-    - FixedAny
-    - FixedEqual
-    - OnDemandUnlimited
-    - OnDemandMax
-    - Unknown
-  - aliases: # aliases define named sets of credit distribution types
-    - AliasAny:
-      - FixedAny
-      - FixedEqual
-      - OnDemandUnlimited
-      - OnDemandMax
-    - AliasFixed:
-      - FixedAny
-      - FixedEqual
-      - OnDemandUnlimited
-      - OnDemandMax
-    - AliasOnDemand:
-      - OnDemandUnlimited
-      - OnDemandMax
\ No newline at end of file
diff --git a/logic/src/test/resources/credit-group-lab.yaml b/logic/src/test/resources/credit-group-lab.yaml
new file mode 100644 (file)
index 0000000..0f45541
--- /dev/null
@@ -0,0 +1,11 @@
+credit_group:
+  name: Lab
+  label: lab
+  owner: some:uri # another group or user
+  members:
+    - memberURI_1 # Can be teaching assistant
+    - memberURI_2 # Can be a student
+    - memberURI_3
+  credit_distribution:
+    - when: OnCreditArrival
+    - how: FixedEqual
diff --git a/logic/src/test/resources/credit-holder-protos.yaml b/logic/src/test/resources/credit-holder-protos.yaml
deleted file mode 100644 (file)
index 8b6266a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-credit-holder-protos:
-  - Single:
-      id: "gr.grnet.aquarium.credits.model.holder.Single"
-  - Composite:
-      id: "gr.grnet.aquarium.credits.model.holder.Composite"
\ No newline at end of file
diff --git a/logic/src/test/resources/credit-structure-greek-uni.yaml b/logic/src/test/resources/credit-structure-greek-uni.yaml
deleted file mode 100644 (file)
index ff2bcb7..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-# Definition of a client type (read: Company, Organization, …)
-
-# This is not necessarily the organizational structure of the client.
-# It may reflect the organizational structure but it actually is the credit structure of the particular client.
-# The credit structure defines the ways that credits can be distributed among the participants.
-#
-# The idea is to provide the policy here and map it to our low-end, generic credit transfer/grouping
-# mechanism(s).
-
-# Also, these structures are kind of static and are considered integral part of the business case each client
-# represents/is characterized by.
-
-structure_class:
-  id: "gr.grnet.aquarium.credit.struct.GreekUniversityCreditStructure"
-  name: Greek University Structure
-  credit_holders:
-    - University:
-      name: University # if omitted, taken as the credit_holders key (University in this case)
-      id: University   # if omitted, taken as the name (University in this case)
-      type: Composite  # if omitted, inferred by the presence of members
-      members:
-        - Department:      # Use the id here and not the name
-          credit_distribution:  # List of credit distribution types
-            - AliasFixed # only specific amounts are given from Universities to Departments
-        - Lab:
-          credit_distribution:
-            - AliasFixed # only specific amounts are given from Universities to Labs
-    - Department:
-      members:
-        - Professor:
-          credit_distribution:
-            - AliasAny # A Department has the ability to distribute credits to its Professors in the most flexible way
-        - Lab:
-          credit_distribution:
-            - AliasAny # A Department has the ability to distribute credits to its Labs in the most flexible way
-        - Course:
-          credit_distribution:
-            - AliasAny # A Department has the ability to distribute credits to its Courses in the most flexible way
-        - Student: # Is this a undergrad, a postgrad, a PhD?
-          credit_distribution:
-            - AliasFixed # only fixed amounts of credits are distributed to Students
-
-    - Lab:
-      members:
-        - Course:
-          credit_distribution:
-            - AliasFixed # Lab members get only fixed amounts
-    - Course:
-      members:
-        - Professor # If no credit distribution is defined, then AliasAny is assumed
-        - Exercise
-        - Student
-    - Professor
-    - Student
-    - Exercise
-
-  distribution: # describes the policy for the distribution of credits
-
index 11d0af0..3fe5b11 100644 (file)
@@ -3,50 +3,58 @@ package test
 
 import org.junit.Test
 import org.junit.Assert._
-import gr.grnet.aquarium.logic.credits.dsl.CreditsDSL
-import gr.grnet.aquarium.logic.credits.model.CreditStructureClass
 import java.io.{Reader, InputStreamReader, InputStream, StringReader}
-import gr.grnet.aquarium.util.yaml.YAMLHelpers
-import gr.grnet.aquarium.logic.credits.model.CreditStructureClass._
 import gr.grnet.aquarium.util.Loggable
+import gr.grnet.aquarium.util.yaml.{YAMLNode, YAMLHelpers}
+import gr.grnet.aquarium.logic.credits.model.GroupCreditHolder
 
 class CreditDSLTest extends Loggable {
 
   object Keys {
-    val StructureClass = "structure_class"
-    val Id = "id"
-    val Name = "name"
-    val Units = "units"
-    val Grouping = "grouping"
+    val credit_group = "credit_group"
+    val name = "name"
+    val label = "label"
+    val owner = "owner"
+    val members = "members"
+    val credit_distribution = "credit_distribution"
   }
 
-  def parseString(s: CharSequence): CreditStructureClass = {
+  def parseResource(name: String): GroupCreditHolder = {
+    parseStream(getClass.getClassLoader.getResourceAsStream(name))
+  }
+
+  def parseString(s: CharSequence): GroupCreditHolder = {
     doParse(new StringReader(s.toString))
   }
 
-  def parseStream(in: InputStream, encoding: String = "UTF-8", closeIn: Boolean = true): CreditStructureClass = {
+  def parseStream(in: InputStream, encoding: String = "UTF-8", closeIn: Boolean = true): GroupCreditHolder = {
     doParse(new InputStreamReader(in, encoding), closeIn)
   }
 
-  // FIXME: implement
-  private def doParse(r: Reader, closeReader: Boolean = true): CreditStructureClass = {
-    val creditsDocument = YAMLHelpers.loadYAML(r, closeReader)
+  def parseChild[T](node: YAMLNode, name: String): YAMLNode = {
+    val y = node / name
+    val yname = y.name
+    assert(name == yname, "Parsed name [%s] equals requested name [%s]".format(yname, name))
+    logger.debug("Parsed [%s] %s".format(yname, y))
+    y
+  }
 
-    val ystructureDef = creditsDocument / Keys.StructureClass
-    val yId = ystructureDef / Keys.Id
-    val yname  = ystructureDef / Keys.Name
-    val yunits = ystructureDef / Keys.Units
-    val ygrouping = ystructureDef / Keys.Grouping
+  // FIXME: implement
+  private def doParse(r: Reader, closeReader: Boolean = true): GroupCreditHolder = {
+    val document = YAMLHelpers.loadYAML(r, closeReader)
 
-    logger.debug("name = %s".format(yname))
-    logger.debug("units = %s".format(yunits))
-    logger.debug("grouping = %s".format(ygrouping))
+    val ygroup = parseChild(document, Keys.credit_group)
+    val yname = parseChild(ygroup, Keys.name)
+    val yabel = parseChild(ygroup, Keys.label)
+    val yowner = parseChild(ygroup, Keys.owner)
+    val ymembers = parseChild(ygroup, Keys.members)
+    val ydistrib = parseChild(ygroup, Keys.credit_distribution)
 
-    CreditStructureClass("", "", Nil)
+    GroupCreditHolder("", "", Nil, Nil)
   }
   @Test
   def testDSLLoad = {
-    val structure = CreditsDSL.parseStream(getClass.getClassLoader.getResourceAsStream("credit-structure-greek-uni.yaml"))
+    val structure = parseResource("credit-group-lab.yaml")
     assertNotNull(structure)
   }
 }
\ No newline at end of file