From: Christos KK Loverdos Date: Mon, 31 Oct 2011 13:41:06 +0000 (+0200) Subject: Reorganize credit model and enhance the YAML nodes with path info X-Git-Tag: aquarium-0.0.1~36 X-Git-Url: https://code.grnet.gr/git/aquarium/commitdiff_plain/848295ae4c9f991b4920dcd5fb8065cbeef69b58 Reorganize credit model and enhance the YAML nodes with path info --- diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/dsl/CreditsDSL.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/dsl/CreditsDSL.scala index a3d827f..7accffe 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/dsl/CreditsDSL.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/dsl/CreditsDSL.scala @@ -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 . */ 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 diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditAmount.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditAmount.scala index 84bb122..66206da 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditAmount.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditAmount.scala @@ -7,4 +7,4 @@ package gr.grnet.aquarium.logic.credits.model * * @author Christos KK Loverdos . */ -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 index 0000000..7a50e26 --- /dev/null +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionHow.scala @@ -0,0 +1,46 @@ +package gr.grnet.aquarium.logic.credits.model + +/** + * + * @author Christos KK Loverdos . + */ +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 index 0000000..8033fa7 --- /dev/null +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionPolicy.scala @@ -0,0 +1,7 @@ +package gr.grnet.aquarium.logic.credits.model + +/** + * + * @author Christos KK Loverdos . + */ +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 index f9ce387..0000000 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionType.scala +++ /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 . - */ -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 . - */ -sealed abstract class CreditDistributionTypeSkeleton(_name: String, _value: Int) extends CreditDistributionType { - def name = _name - def value = _value -} - -/** - * - * @author Christos KK Loverdos . - */ -case object FixedAnyCreditDistributionType - extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.FixedAny, CreditDistributionType.Values.FixedEqual) { - - override def isFixedAny = true -} - -/** - * - * @author Christos KK Loverdos . - */ -case object FixedEqualCreditDistributionType - extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.FixedAny, CreditDistributionType.Values.FixedEqual) { - - override def isFixedEqual = true -} - -/** - * - * @author Christos KK Loverdos . - */ -case object OnDemandUnlimitedCreditDistributionType - extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.OnDemandUnlimited, CreditDistributionType.Values.OnDemandUnlimited) { - - override def isOnDemandUnlimited = true -} - -/** - * - * @author Christos KK Loverdos . - */ -case object OnDemandMaxCreditDistributionType - extends CreditDistributionTypeSkeleton(CreditDistributionType.Names.OnDemandMax, CreditDistributionType.Values.OnDemandMax) { - - override def isOnDemandMax = true -} - -/** - * - * @author Christos KK Loverdos . - */ -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 index 0000000..9c85d7e --- /dev/null +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditDistributionWhen.scala @@ -0,0 +1,33 @@ +package gr.grnet.aquarium.logic.credits.model + +/** + * + * @author Christos KK Loverdos . + */ +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 diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolder.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolder.scala index 2923c37..988dc16 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolder.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolder.scala @@ -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 . */ -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 index b657c0e..0000000 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditHolderClass.scala +++ /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 . - */ -sealed trait CreditHolderClass { - def name: String - def isSingleHolderClass: Boolean - def isCompositeHolderClass: Boolean - def members: List[CreditHolderClass] - def creditDistributions: MembersCreditDistributionMap -} - -/** - * - * @author Christos KK Loverdos . - */ -case class SingleCreditHolderClass(name: String) extends CreditHolderClass { - def members = Nil - def creditDistributions = Map() - def isSingleHolderClass = true - def isCompositeHolderClass = false -} - -/** - * - * @author Christos KK Loverdos . - */ -case class CompositeCreditHolderClass( - name: String, - members: List[CreditHolderClass], - creditDistributions: MembersCreditDistributionMap) - extends CreditHolderClass { - - def isSingleHolderClass = true - def isCompositeHolderClass = true -} \ No newline at end of file diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditOrigin.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditOrigin.scala index bf9d14d..9d864b8 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditOrigin.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditOrigin.scala @@ -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 index c1b0cb9..0000000 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructure.scala +++ /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 . - */ -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 index 17bec3e..0000000 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/CreditStructureClass.scala +++ /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 . - */ -case class CreditStructureClass( - id: String, - name: String, - memberClasses: List[CreditHolderClass]) diff --git a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/package.scala b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/package.scala index 790bd30..026af8b 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/package.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/logic/credits/model/package.scala @@ -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 diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala index 24caa07..6b2c888 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala @@ -4,10 +4,12 @@ package gr.grnet.aquarium.util.yaml * * @author Georgios Gousios . */ -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) } diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala index 4b74e6b..0f5df19 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala @@ -8,5 +8,8 @@ case object YAMLEmptyNode extends YAMLNode { def /(childName: String) = YAMLEmptyNode override def isEmpty = true + + def path = "" + def withPath(newPath: String) = this } diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala index 5233a00..dfc2542 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala @@ -4,10 +4,12 @@ package gr.grnet.aquarium.util.yaml * * @author Georgios Gousios . */ -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) } diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala index a77511f..557465e 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala @@ -4,7 +4,7 @@ package gr.grnet.aquarium.util.yaml * * @author Christos KK Loverdos . */ -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 diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala index f43c8b8..de915db 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala @@ -6,12 +6,14 @@ import collection.mutable * * @author Christos KK Loverdos . */ -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) } diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala index 78bb96e..b3ca950 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala @@ -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 . */ 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 => diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala index c73c58e..23fceaf 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala @@ -4,10 +4,12 @@ package gr.grnet.aquarium.util.yaml * * @author Christos KK Loverdos . */ -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) } diff --git a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala index 8093709..c4d566c 100644 --- a/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala +++ b/logic/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala @@ -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 index 0000000..2e35463 --- /dev/null +++ b/logic/src/test/resources/credit-distribution-policies.yaml @@ -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 index 0d2ebe4..0000000 --- a/logic/src/test/resources/credit-distribution-types.yaml +++ /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 index 0000000..0f45541 --- /dev/null +++ b/logic/src/test/resources/credit-group-lab.yaml @@ -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 index 8b6266a..0000000 --- a/logic/src/test/resources/credit-holder-protos.yaml +++ /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 index ff2bcb7..0000000 --- a/logic/src/test/resources/credit-structure-greek-uni.yaml +++ /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 - diff --git a/logic/src/test/scala/gr/grnet/aquarium/logic/test/CreditDSLTest.scala b/logic/src/test/scala/gr/grnet/aquarium/logic/test/CreditDSLTest.scala index 11d0af0..3fe5b11 100644 --- a/logic/src/test/scala/gr/grnet/aquarium/logic/test/CreditDSLTest.scala +++ b/logic/src/test/scala/gr/grnet/aquarium/logic/test/CreditDSLTest.scala @@ -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