Second cut of the new policy configuration system
authorChristos KK Loverdos <loverdos@gmail.com>
Fri, 6 Jul 2012 11:36:56 +0000 (14:36 +0300)
committerChristos KK Loverdos <loverdos@gmail.com>
Fri, 6 Jul 2012 11:36:56 +0000 (14:36 +0300)
Major changes. Does not compile. Will need a third round.

82 files changed:
src/main/resources/aquarium.properties
src/main/resources/policy.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/Aquarium.scala
src/main/scala/gr/grnet/aquarium/AquariumBuilder.scala
src/main/scala/gr/grnet/aquarium/Timespan.scala
src/main/scala/gr/grnet/aquarium/actor/service/user/UserActor.scala
src/main/scala/gr/grnet/aquarium/charging/ChargingBehavior.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLCostPolicy.scala with 66% similarity]
src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorNames.scala [moved from src/main/scala/gr/grnet/aquarium/store/StoreException.scala with 85% similarity]
src/main/scala/gr/grnet/aquarium/charging/ChargingInput.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLCostPolicyVar.scala with 51% similarity]
src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceState.scala [moved from src/main/scala/gr/grnet/aquarium/computation/state/parts/AgreementHistoryItem.scala with 58% similarity]
src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceStateNames.scala [moved from src/main/scala/gr/grnet/aquarium/policy/ChargingBehavior.scala with 91% similarity]
src/main/scala/gr/grnet/aquarium/computation/Chargeslot.scala
src/main/scala/gr/grnet/aquarium/computation/TimeslotComputations.scala
src/main/scala/gr/grnet/aquarium/computation/UserStateComputations.scala
src/main/scala/gr/grnet/aquarium/computation/state/UserState.scala
src/main/scala/gr/grnet/aquarium/computation/state/UserStateBootstrap.scala
src/main/scala/gr/grnet/aquarium/computation/state/UserStateWorker.scala
src/main/scala/gr/grnet/aquarium/computation/state/parts/AgreementHistory.scala
src/main/scala/gr/grnet/aquarium/event/model/NewWalletEntry.scala
src/main/scala/gr/grnet/aquarium/event/model/PolicyEntry.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/Policy.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/CostPolicyAlgorithmCompiler.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/ExecutableChargingBehaviorAlgorithm.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/ExecutableCostPolicyAlgorithm.scala with 90% similarity]
src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleCostPolicyAlgorithmCompiler.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm$.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableCostPolicyAlgorithm.scala with 62% similarity]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLAgreement.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLAlgorithm.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLCreditPlan.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLCronSpec.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLPolicy.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLPriceList.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLResource.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLSemanticChecks.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLTimeBoundedItem.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLTimeFrame.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLTimeFrameRepeat.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLTimeSpec.scala [deleted file]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLUtils.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Timeslot.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Vocabulary.scala [deleted file]
src/main/scala/gr/grnet/aquarium/policy/ChargingType.scala [deleted file]
src/main/scala/gr/grnet/aquarium/policy/EffectiveUnitPrice.scala
src/main/scala/gr/grnet/aquarium/policy/FullPriceTable.scala
src/main/scala/gr/grnet/aquarium/policy/PolicyModel.scala
src/main/scala/gr/grnet/aquarium/policy/ResourceType.scala
src/main/scala/gr/grnet/aquarium/policy/StdPolicy.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLItem.scala with 77% similarity]
src/main/scala/gr/grnet/aquarium/policy/StdUserAgreement.scala [moved from src/main/scala/gr/grnet/aquarium/util/yaml/YAMLLongNode.scala with 81% similarity]
src/main/scala/gr/grnet/aquarium/policy/UserAgreementModel.scala
src/main/scala/gr/grnet/aquarium/service/RoleableActorProviderService.scala [deleted file]
src/main/scala/gr/grnet/aquarium/simulation/AquariumSim.scala
src/main/scala/gr/grnet/aquarium/simulation/ResourceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthResourceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceResourceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeInstanceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeResourceSim.scala
src/main/scala/gr/grnet/aquarium/store/PolicyStore.scala
src/main/scala/gr/grnet/aquarium/store/memory/MemStoreProvider.scala
src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBPolicy.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLResourcesMap.scala with 68% similarity]
src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBStore.scala
src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBStoreProvider.scala
src/main/scala/gr/grnet/aquarium/util/CollectionUtils.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/DateUtils.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/xstream/ListConverter.scala
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLBooleanNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLHelpers.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala [deleted file]
src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala [deleted file]
src/test/resources/aquarium.properties
src/test/scala/gr/grnet/aquarium/computation/TimeslotComputationsTest.scala [deleted file]
src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala [deleted file]
src/test/scala/gr/grnet/aquarium/logic/test/DSLTestBase.scala [deleted file]
src/test/scala/gr/grnet/aquarium/logic/test/DSLUtilsTest.scala [deleted file]
src/test/scala/gr/grnet/aquarium/logic/test/DateUtilsTest.scala [deleted file]
src/test/scala/gr/grnet/aquarium/logic/test/PerfTest.scala [deleted file]
src/test/scala/gr/grnet/aquarium/user/UserStateComputationsTest.scala

index 9b2569e..dfaadec 100644 (file)
@@ -48,8 +48,8 @@ mongodb.username=aquarium
 # Password for connecting to the persistence service
 mongodb.password=aquarium
 
-# The name of the DB schema to use
-mongodb.dbschema=aquarium
+# The name of the MongoDB database to use
+mongodb.database=aquarium
 
 ### Performance options
 
diff --git a/src/main/resources/policy.scala b/src/main/resources/policy.scala
new file mode 100644 (file)
index 0000000..4b9544c
--- /dev/null
@@ -0,0 +1,29 @@
+import gr.grnet.aquarium.charging.{ContinuousChargingBehavior, OnOffChargingBehavior, DiscreteChargingBehavior}
+import gr.grnet.aquarium.policy.{EffectiveUnitPrice, EffectivePriceTable, FullPriceTable, ResourceType, StdPolicy}
+import gr.grnet.aquarium.Timespan
+
+// Definition of our standard policy in plain Scala
+// This will be dynamically interpreted during Aquarium startup
+
+StdPolicy(
+    id = "policy-1",
+    parentID = None,
+    validityTimespan = Timespan(0),
+    resourceTypes = Set(
+      ResourceType("bandwidth", "MB/Hr", DiscreteChargingBehavior),
+      ResourceType("vmtime",    "Hr",    OnOffChargingBehavior),
+      ResourceType("diskspace", "MB/Hr", ContinuousChargingBehavior)
+    ),
+    chargingBehaviorClasses = Set(
+      DiscreteChargingBehavior.getClass.getName,
+      OnOffChargingBehavior.getClass.getName,
+      ContinuousChargingBehavior.getClass.getName
+    ),
+    roleMapping = Map(
+      "default" -> FullPriceTable(Map(
+        "bandwidth" -> EffectivePriceTable(EffectiveUnitPrice(0.01, Nil) :: Nil),
+        "vmtime"    -> EffectivePriceTable(EffectiveUnitPrice(0.01, Nil) :: Nil),
+        "diskspace" -> EffectivePriceTable(EffectiveUnitPrice(0.01, Nil) :: Nil)
+      ))
+    )
+  )
\ No newline at end of file
index 62b5a13..a31281e 100644 (file)
@@ -41,18 +41,16 @@ import com.ckkloverdos.props.Props
 import gr.grnet.aquarium.store.{PolicyStore, UserStateStore, IMEventStore, ResourceEventStore, StoreProvider}
 import java.io.File
 import gr.grnet.aquarium.util.{Loggable, Lifecycle}
-import gr.grnet.aquarium.service.{RoleableActorProviderService, StoreWatcherService, RabbitMQService, TimerService, EventBusService, AkkaService}
+import gr.grnet.aquarium.service.{StoreWatcherService, RabbitMQService, TimerService, EventBusService, AkkaService}
 import com.ckkloverdos.convert.Converters
 import java.util.concurrent.atomic.AtomicBoolean
 import org.slf4j.{LoggerFactory, Logger}
-import gr.grnet.aquarium.logic.accounting.algorithm.CostPolicyAlgorithmCompiler
 import gr.grnet.aquarium.computation.UserStateComputations
 import com.ckkloverdos.maybe._
 import gr.grnet.aquarium.ResourceLocator._
-import gr.grnet.aquarium.logic.accounting.dsl.DSLResourcesMap
-import gr.grnet.aquarium.logic.accounting.Policy
 import com.ckkloverdos.sys.SysProp
 import gr.grnet.aquarium.service.event.AquariumCreatedEvent
+import gr.grnet.aquarium.policy.{PolicyDefinedFullPriceTableRef, StdUserAgreement, UserAgreementModel, ResourceType}
 
 /**
  *
@@ -230,14 +228,14 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable {
 
   }
 
-  def currentResourcesMap: DSLResourcesMap = {
-    // FIXME: Get rid of this singleton stuff
-    Policy.policy.resourcesMap
+  def currentResourceTypesMap: Map[String, ResourceType] = {
+    // FIXME: Implement
+    Map()
   }
 
-  def initialAgreementForRole(role: String, referenceTimeMillis: Long): String = {
+  def initialUserAgreementForRole(role: String, referenceTimeMillis: Long): UserAgreementModel = {
     // FIXME: Where is the mapping?
-    "default"
+    StdUserAgreement("", None, Timespan(0L), defaultInitialUserRole, PolicyDefinedFullPriceTableRef)
   }
 
   def initialBalanceForRole(role: String, referenceTimeMillis: Long): Double = {
@@ -262,8 +260,6 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable {
 
   def eventsStoreFolder = apply(EnvKeys.eventsStoreFolder)
 
-  def algorithmCompiler = apply(EnvKeys.algorithmCompiler)
-
   def eventBus = apply(EnvKeys.eventBus)
 
   def userStateComputations = apply(EnvKeys.userStateComputations)
@@ -274,8 +270,6 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable {
 
   def converters = apply(EnvKeys.converters)
 
-//  def actorProvider = apply(EnvKeys.actorProvider)
-
   def saveResourceEventsToEventsStoreFolder = apply(EnvKeys.eventsStoreSaveRCEvents)
 
   def saveIMEventsToEventsStoreFolder = apply(EnvKeys.eventsStoreSaveIMEvents)
@@ -407,13 +401,6 @@ object Aquarium {
     final val restService: TypedKey[Lifecycle] =
       new AquariumEnvKey[Lifecycle]("rest.service.class")
 
-    /**
-     * The fully qualified name of the class that implements the `RoleableActorProviderService`.
-     * Will be instantiated reflectively and should have a public default constructor.
-     */
-//    final val actorProvider: TypedKey[RoleableActorProviderService] =
-//      new AquariumEnvKey[RoleableActorProviderService]("actor.provider.class")
-
     final val akkaService: TypedKey[AkkaService] =
       new AquariumEnvKey[AkkaService]("akka.service")
 
@@ -432,9 +419,6 @@ object Aquarium {
     final val converters: TypedKey[Converters] =
       new AquariumEnvKey[Converters]("converters")
 
-    final val algorithmCompiler: TypedKey[CostPolicyAlgorithmCompiler] =
-      new AquariumEnvKey[CostPolicyAlgorithmCompiler]("algorithm.compiler")
-
     final val userStateComputations: TypedKey[UserStateComputations] =
       new AquariumEnvKey[UserStateComputations]("user.state.computations")
 
index 7b41d5b..e1ec73c 100644 (file)
@@ -372,8 +372,6 @@ final class AquariumBuilder(val originalProps: Props) extends Loggable {
       newInstance(envKey.keyType, classOf[SimpleTimerService].getName)
     }
 
-    checkNoPropsOverride(EnvKeys.algorithmCompiler) { _ ⇒ SimpleCostPolicyAlgorithmCompiler }
-
     checkNoPropsOverride(EnvKeys.userStateComputations) { envKey ⇒
       newInstance(envKey.keyType, classOf[UserStateComputations].getName)
     }
index ecc8654..0f4dbb7 100644 (file)
@@ -35,6 +35,8 @@
 
 package gr.grnet.aquarium
 
+import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
+
 /**
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
@@ -44,4 +46,6 @@ case class Timespan(fromMillis: Long, toMillis: Long = Long.MaxValue) {
   def extendsToInfinity: Boolean = toMillis == Long.MaxValue
 
   def extendToInfinity: Timespan = Timespan(fromMillis, Long.MaxValue)
+
+  def toTimeslot = Timeslot(fromMillis, toMillis)
 }
index ec22e55..79fb3e4 100644 (file)
@@ -172,8 +172,7 @@ class UserActor extends ReflectiveRoleableActor {
     val userStateBootstrap = UserStateBootstrap(
       this._userID,
       userCreationMillis,
-      initialRole,
-      aquarium.initialAgreementForRole(initialRole, userCreationMillis),
+      aquarium.initialUserAgreementForRole(initialRole, userCreationMillis),
       aquarium.initialBalanceForRole(initialRole, userCreationMillis)
     )
 
@@ -182,7 +181,7 @@ class UserActor extends ReflectiveRoleableActor {
       BillingMonthInfo.fromMillis(now),
       now,
       userStateBootstrap,
-      aquarium.currentResourcesMap,
+      aquarium.currentResourceTypesMap,
       InitialUserActorSetup(),
       stdUserStateStoreFunc,
       None
@@ -327,21 +326,20 @@ class UserActor extends ReflectiveRoleableActor {
     val userID = this._userID
     val userCreationMillis = this._imState.userCreationMillis.get
     val initialRole = this._imState.roleHistory.firstRoleName.getOrElse(aquarium.defaultInitialUserRole)
-    val initialAgreement = aquarium.initialAgreementForRole(initialRole, userCreationMillis)
+    val initialAgreement = aquarium.initialUserAgreementForRole(initialRole, userCreationMillis)
     val initialCredits   = aquarium.initialBalanceForRole(initialRole, userCreationMillis)
     val userStateBootstrap = UserStateBootstrap(
       userID,
       userCreationMillis,
-      initialRole,
       initialAgreement,
       initialCredits
     )
     val billingMonthInfo = BillingMonthInfo.fromMillis(now)
-    val currentResourcesMap = aquarium.currentResourcesMap
+    val currentResourcesMap = aquarium.currentResourceTypesMap
     val calculationReason = RealtimeBillingCalculation(None, now)
     val eventOccurredMillis = rcEvent.occurredMillis
 
-//    DEBUG("Using %s", currentResourcesMap.toJsonString)
+//    DEBUG("Using %s", currentResourceTypesMap.toJsonString)
 
     this._userState = aquarium.userStateComputations.doMonthBillingUpTo(
       billingMonthInfo,
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.logic.accounting.dsl
+package gr.grnet.aquarium.charging
 
-import com.ckkloverdos.maybe.{NoVal, Failed, Just, Maybe}
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
 import gr.grnet.aquarium.{AquariumInternalError, AquariumException}
 
 /**
- * A cost policy indicates how charging for a resource will be done
+ * A charging behavior indicates how charging for a resource will be done
  * wrt the various states a resource can be.
  *
- * @author Georgios Gousios <gousiosg@gmail.com>
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-abstract class DSLCostPolicy(val name: String, val vars: Set[DSLCostPolicyVar]) extends DSLItem {
+abstract class ChargingBehavior(val name: String, val inputs: Set[ChargingInput]) {
 
-  def varNames = vars.map(_.name)
+  final lazy val inputNames = inputs.map(_.name)
 
   /**
-   * Generate a map where the key is a [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]]
+   * Generate a map where the key is a [[gr.grnet.aquarium.charging.ChargingInput]]
    * and the value the respective value. This map will be used to do the actual credit charge calculation
    * by the respective algorithm.
    *
    * Values are obtained from a corresponding context, which is provided by the parameters. We assume that this context
    * has been validated before the call to `makeValueMap` is made.
    *
-   * @param totalCredits   the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLTotalCreditsVar]]
-   * @param oldTotalAmount the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLOldTotalAmountVar]]
-   * @param newTotalAmount the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLNewTotalAmountVar]]
-   * @param timeDelta      the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLTimeDeltaVar]]
-   * @param previousValue  the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLPreviousValueVar]]
-   * @param currentValue   the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLCurrentValueVar]]
-   * @param unitPrice      the value for [[gr.grnet.aquarium.logic.accounting.dsl.DSLUnitPriceVar]]
+   * @param totalCredits   the value for [[gr.grnet.aquarium.charging.TotalCreditsInput.]]
+   * @param oldTotalAmount the value for [[gr.grnet.aquarium.charging.OldTotalAmountInput]]
+   * @param newTotalAmount the value for [[gr.grnet.aquarium.charging.NewTotalAmountInput]]
+   * @param timeDelta      the value for [[gr.grnet.aquarium.charging.TimeDeltaInput]]
+   * @param previousValue  the value for [[gr.grnet.aquarium.charging.PreviousValueInput]]
+   * @param currentValue   the value for [[gr.grnet.aquarium.charging.CurrentValueInput]]
+   * @param unitPrice      the value for [[gr.grnet.aquarium.charging.UnitPriceInput]]
    *
-   * @return a map from [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]]s to respective values.
+   * @return a map from [[gr.grnet.aquarium.charging.ChargingInput]]s to respective values.
    */
-  def makeValueMap(totalCredits: Double,
-                   oldTotalAmount: Double,
-                   newTotalAmount: Double,
-                   timeDelta: Double,
-                   previousValue: Double,
-                   currentValue: Double,
-                   unitPrice: Double): Map[DSLCostPolicyVar, Any] = {
-
-    DSLCostPolicy.makeValueMapFor(
+  def makeValueMap(
+      totalCredits: Double,
+      oldTotalAmount: Double,
+      newTotalAmount: Double,
+      timeDelta: Double,
+      previousValue: Double,
+      currentValue: Double,
+      unitPrice: Double
+  ): Map[ChargingInput, Any] = {
+
+    ChargingBehavior.makeValueMapFor(
       this,
       totalCredits,
       oldTotalAmount,
@@ -93,7 +93,7 @@ abstract class DSLCostPolicy(val name: String, val vars: Set[DSLCostPolicyVar])
   def needsPreviousEventForCreditAndAmountCalculation: Boolean = {
     // If we need any variable that is related to the previous event
     // then we do need a previous event
-    vars.exists(_.isDirectlyRelatedToPreviousEvent)
+    inputs.exists(_.isDirectlyRelatedToPreviousEvent)
   }
 
   /**
@@ -101,7 +101,7 @@ abstract class DSLCostPolicy(val name: String, val vars: Set[DSLCostPolicyVar])
    * (see [[gr.grnet.aquarium.computation.state.parts.ResourceInstanceSnapshot]]), the
    * value arriving in a new resource event and the new details, compute the new instance amount.
    *
-   * Note that the `oldAmount` does not make sense for all types of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicy]],
+   * Note that the `oldAmount` does not make sense for all types of [[gr.grnet.aquarium.charging.ChargingBehavior]],
    * in which case it is ignored.
    *
    * @param oldAmount     the old accumulating amount
@@ -133,7 +133,7 @@ abstract class DSLCostPolicy(val name: String, val vars: Set[DSLCostPolicyVar])
    * Typically all events are billable by default and indeed this is the default implementation
    * provided here.
    *
-   * The only exception to the rule is ON events for [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]].
+   * The only exception to the rule is ON events for [[gr.grnet.aquarium.charging.OnOffChargingBehavior]].
    */
   def isBillableEvent(event: ResourceEventModel): Boolean = false
 
@@ -166,7 +166,7 @@ abstract class DSLCostPolicy(val name: String, val vars: Set[DSLCostPolicyVar])
    * There are resources (cost policies) for which implicit events must be generated at the end of the billing period
    * and also at the beginning of the next one. For these cases, this method must return `true`.
    *
-   * The motivating example comes from the [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]] for which we
+   * The motivating example comes from the [[gr.grnet.aquarium.charging.OnOffChargingBehavior]] for which we
    * must implicitly assume `OFF` events at the end of the billing period and `ON` events at the beginning of the next
    * one.
    *
@@ -179,65 +179,61 @@ abstract class DSLCostPolicy(val name: String, val vars: Set[DSLCostPolicyVar])
   def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, newOccurredMillis: Long): ResourceEventModel
 }
 
-object DSLCostPolicyNames {
-  final val onoff      = "onoff"
-  final val discrete   = "discrete"
-  final val continuous = "continuous"
-  final val once       = "once"
-}
-
-object DSLCostPolicy {
-  def apply(name: String): DSLCostPolicy  = {
+object ChargingBehavior {
+  def apply(name: String): ChargingBehavior  = {
     name match {
       case null ⇒
-        throw new DSLParseException("<null> cost policy")
+        throw new AquariumException("<null> charging behavior")
 
       case name ⇒ name.toLowerCase match {
-        case DSLCostPolicyNames.onoff      ⇒ OnOffCostPolicy
-        case DSLCostPolicyNames.discrete   ⇒ DiscreteCostPolicy
-        case DSLCostPolicyNames.continuous ⇒ ContinuousCostPolicy
-        case DSLCostPolicyNames.once       ⇒ ContinuousCostPolicy
+        case ChargingBehaviorNames.onoff      ⇒ OnOffChargingBehavior
+        case ChargingBehaviorNames.discrete   ⇒ DiscreteChargingBehavior
+        case ChargingBehaviorNames.continuous ⇒ ContinuousChargingBehavior
+        case ChargingBehaviorNames.once       ⇒ ContinuousChargingBehavior
 
         case _ ⇒
-          throw new DSLParseException("Invalid cost policy %s".format(name))
+          throw new AquariumException("Invalid charging behavior %s".format(name))
       }
     }
   }
 
-  def makeValueMapFor(costPolicy: DSLCostPolicy,
-                      totalCredits: Double,
-                      oldTotalAmount: Double,
-                      newTotalAmount: Double,
-                      timeDelta: Double,
-                      previousValue: Double,
-                      currentValue: Double,
-                      unitPrice: Double): Map[DSLCostPolicyVar, Any] = {
-    val vars = costPolicy.vars
-    var map = Map[DSLCostPolicyVar, Any]()
-
-    if(vars contains DSLCostPolicyNameVar) map += DSLCostPolicyNameVar -> costPolicy.name
-    if(vars contains DSLTotalCreditsVar  ) map += DSLTotalCreditsVar   -> totalCredits
-    if(vars contains DSLOldTotalAmountVar) map += DSLOldTotalAmountVar -> oldTotalAmount
-    if(vars contains DSLNewTotalAmountVar) map += DSLNewTotalAmountVar -> newTotalAmount
-    if(vars contains DSLTimeDeltaVar     ) map += DSLTimeDeltaVar      -> timeDelta
-    if(vars contains DSLPreviousValueVar ) map += DSLPreviousValueVar  -> previousValue
-    if(vars contains DSLCurrentValueVar  ) map += DSLCurrentValueVar   -> currentValue
-    if(vars contains DSLUnitPriceVar     ) map += DSLUnitPriceVar      -> unitPrice
+  def makeValueMapFor(
+      chargingBehavior: ChargingBehavior,
+      totalCredits: Double,
+      oldTotalAmount: Double,
+      newTotalAmount: Double,
+      timeDelta: Double,
+      previousValue: Double,
+      currentValue: Double,
+      unitPrice: Double
+  ): Map[ChargingInput, Any] = {
+    
+    val inputs = chargingBehavior.inputs
+    var map = Map[ChargingInput, Any]()
+
+    if(inputs contains ChargingBehaviorNameInput) map += ChargingBehaviorNameInput -> chargingBehavior.name
+    if(inputs contains TotalCreditsInput  ) map += TotalCreditsInput   -> totalCredits
+    if(inputs contains OldTotalAmountInput) map += OldTotalAmountInput -> oldTotalAmount
+    if(inputs contains NewTotalAmountInput) map += NewTotalAmountInput -> newTotalAmount
+    if(inputs contains TimeDeltaInput     ) map += TimeDeltaInput      -> timeDelta
+    if(inputs contains PreviousValueInput ) map += PreviousValueInput  -> previousValue
+    if(inputs contains CurrentValueInput  ) map += CurrentValueInput   -> currentValue
+    if(inputs contains UnitPriceInput     ) map += UnitPriceInput      -> unitPrice
 
     map
   }
 }
 
 /**
- * A cost policy for which resource events just carry a credit amount that will be added to the total one.
+ * A charging behavior for which resource events just carry a credit amount that will be added to the total one.
  *
  * Examples are: a) Give a gift of X credits to the user, b) User bought a book, so charge for the book price.
  *
  */
-case object OnceCostPolicy
-extends DSLCostPolicy(
-    DSLCostPolicyNames.once,
-    Set(DSLCostPolicyNameVar, DSLCurrentValueVar)
+case object OnceChargingBehavior
+extends ChargingBehavior(
+    ChargingBehaviorNames.once,
+    Set(ChargingBehaviorNameInput, CurrentValueInput)
 ) {
 
   /**
@@ -272,10 +268,10 @@ extends DSLCostPolicy(
  * Example resource that might be adept to a continuous policy
  * is diskspace.
  */
-case object ContinuousCostPolicy
-extends DSLCostPolicy(
-    DSLCostPolicyNames.continuous,
-    Set(DSLCostPolicyNameVar, DSLUnitPriceVar, DSLOldTotalAmountVar, DSLTimeDeltaVar)
+case object ContinuousChargingBehavior
+extends ChargingBehavior(
+    ChargingBehaviorNames.continuous,
+    Set(ChargingBehaviorNameInput, UnitPriceInput, OldTotalAmountInput, TimeDeltaInput)
 ) {
 
   def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = {
@@ -322,7 +318,7 @@ extends DSLCostPolicy(
 }
 
 /**
- * An onoff cost policy expects a resource to be in one of the two allowed
+ * An onoff charging behavior expects a resource to be in one of the two allowed
  * states (`on` and `off`, respectively). It will charge for resource usage
  * within the timeframes specified by consecutive on and off resource events.
  * An onoff policy is the same as a continuous policy, except for
@@ -331,10 +327,10 @@ extends DSLCostPolicy(
  * Example resources that might be adept to onoff policies are VMs in a
  * cloud application and books in a book lending application.
  */
-case object OnOffCostPolicy
-extends DSLCostPolicy(
-    DSLCostPolicyNames.onoff,
-    Set(DSLCostPolicyNameVar, DSLUnitPriceVar, DSLTimeDeltaVar)
+case object OnOffChargingBehavior
+extends ChargingBehavior(
+    ChargingBehaviorNames.onoff,
+    Set(ChargingBehaviorNameInput, UnitPriceInput, TimeDeltaInput)
 ) {
 
   /**
@@ -353,7 +349,7 @@ extends DSLCostPolicy(
 
   private[this]
   def getValueForCreditCalculation(oldAmount: Double, newEventValue: Double): Double = {
-    import OnOffCostPolicyValues.{ON, OFF}
+    import OnOffChargingBehaviorValues.{ON, OFF}
 
     def exception(rs: OnOffPolicyResourceState) =
       new AquariumException("Resource state transition error (%s -> %s)".format(rs, rs))
@@ -372,7 +368,7 @@ extends DSLCostPolicy(
 
   override def isBillableEvent(event: ResourceEventModel) = {
     // ON events do not contribute, only OFF ones.
-    OnOffCostPolicyValues.isOFFValue(event.value)
+    OnOffChargingBehaviorValues.isOFFValue(event.value)
   }
 
   /**
@@ -392,16 +388,16 @@ extends DSLCostPolicy(
   def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = {
     // If we have ON events with no OFF companions at the end of the billing period,
     // then we must generate implicit OFF events.
-    OnOffCostPolicyValues.isONValue(resourceEvent.value)
+    OnOffChargingBehaviorValues.isONValue(resourceEvent.value)
   }
 
   def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, newOccurredMillis: Long) = {
     assert(supportsImplicitEvents && mustConstructImplicitEndEventFor(resourceEvent))
-    assert(OnOffCostPolicyValues.isONValue(resourceEvent.value))
+    assert(OnOffChargingBehaviorValues.isONValue(resourceEvent.value))
 
     val details = resourceEvent.details
     val newDetails = ResourceEventModel.setAquariumSyntheticAndImplicitEnd(details)
-    val newValue   = OnOffCostPolicyValues.OFF
+    val newValue   = OnOffChargingBehaviorValues.OFF
 
     resourceEvent.withDetailsAndValue(newDetails, newValue, newOccurredMillis)
   }
@@ -411,7 +407,7 @@ extends DSLCostPolicy(
   }
 }
 
-object OnOffCostPolicyValues {
+object OnOffChargingBehaviorValues {
   final val ON  = 1.0
   final val OFF = 0.0
 
@@ -420,7 +416,7 @@ object OnOffCostPolicyValues {
 }
 
 /**
- * An discrete cost policy indicates that a resource should be charged directly
+ * An discrete charging behavior indicates that a resource should be charged directly
  * at each resource state change, i.e. the charging is not dependent on
  * the time the resource.
  *
@@ -428,10 +424,10 @@ object OnOffCostPolicyValues {
  * actions (e.g. the fact that a user has created an account) or resources
  * that should be charged per volume once (e.g. the allocation of a volume)
  */
-case object DiscreteCostPolicy
-extends DSLCostPolicy(
-    DSLCostPolicyNames.discrete,
-    Set(DSLCostPolicyNameVar, DSLUnitPriceVar, DSLCurrentValueVar)
+case object DiscreteChargingBehavior
+extends ChargingBehavior(
+    ChargingBehaviorNames.discrete,
+    Set(ChargingBehaviorNameInput, UnitPriceInput, CurrentValueInput)
 ) {
 
   def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = {
@@ -465,39 +461,3 @@ extends DSLCostPolicy(
     throw new AquariumInternalError("constructImplicitEndEventFor() Not compliant with %s".format(this))
   }
 }
-
-/**
- * Encapsulates the possible states that a resource with an
- * [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]]
- * can be.
- */
-abstract class OnOffPolicyResourceState(val state: String) {
-  def isOn: Boolean = !isOff
-  def isOff: Boolean = !isOn
-}
-
-object OnOffPolicyResourceState {
-  def apply(name: Any): OnOffPolicyResourceState = {
-    name match {
-      case x: String if (x.equalsIgnoreCase(OnOffPolicyResourceStateNames.on))  => OnResourceState
-      case y: String if (y.equalsIgnoreCase(OnOffPolicyResourceStateNames.off)) => OffResourceState
-      case a: Double if (a == 0) => OffResourceState
-      case b: Double if (b == 1) => OnResourceState
-      case i: Int if (i == 0) => OffResourceState
-      case j: Int if (j == 1) => OnResourceState
-      case _ => throw new DSLParseException("Invalid OnOffPolicyResourceState %s".format(name))
-    }
-  }
-}
-
-object OnOffPolicyResourceStateNames {
-  final val on  = "on"
-  final val off = "off"
-}
-
-object OnResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.on) {
-  override def isOn = true
-}
-object OffResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.off) {
-  override def isOff = true
-}
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.store
-
-import gr.grnet.aquarium.AquariumException
+package gr.grnet.aquarium.charging
 
 /**
- * Thrown when an error occurs at the persistence layer.
  *
- * @author Georgios Gousios <gousiosg@gmail.com>
+ * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-class StoreException(msg: String) extends AquariumException(msg)
\ No newline at end of file
+
+object ChargingBehaviorNames {
+  final val onoff      = "onoff"
+  final val discrete   = "discrete"
+  final val continuous = "continuous"
+  final val once       = "once"
+}
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.logic.accounting.dsl
+package gr.grnet.aquarium.charging
 
 /**
- * The type of variable needed in order to compute costs, that is credit charges.
- *
- * A [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicy]] declares which variables
- * it needs in order to compute credit charges. These and only these variables are
- * passed to the repsective [[gr.grnet.aquarium.logic.accounting.dsl.DSLAlgorithm]] (and
- * are also used to type-check the algorithm).
+ * An input that is used in a charging function.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-sealed abstract class DSLCostPolicyVar(val name: String) {
-  def isDirectlyRelatedToPreviousEvent: Boolean = false
-  def isDirectlyRelatedToCurrentEvent: Boolean = false
-}
+
+sealed abstract class ChargingInput(
+    val name: String,
+    val isDirectlyRelatedToPreviousEvent: Boolean = false,
+    val isDirectlyRelatedToCurrentEvent: Boolean = false
+)
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the name of the cost
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the name of the cost
  * policy for which a cost computation applies.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLCostPolicyNameVar extends DSLCostPolicyVar("costPolicyName")
+case object ChargingBehaviorNameInput extends ChargingInput("chargingBehaviorName")
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the total credits.
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the total credits.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLTotalCreditsVar extends DSLCostPolicyVar("totalCredits")
+case object TotalCreditsInput extends ChargingInput("totalCredits")
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the old total (accumulating)
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the old total (accumulating)
  * amount, that is the resource amount before taking into account a new resource event.
  * For example, in the case of `diskspace`, this is the total diskspace used by a user.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLOldTotalAmountVar extends DSLCostPolicyVar("oldTotalAmount")
+case object OldTotalAmountInput extends ChargingInput("oldTotalAmount")
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the new total (accumulating)
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the new total (accumulating)
  * amount, that is the resource amount after taking into account a new resource event.
  * For example, in the case of `diskspace`, this is the total diskspace used by a user.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLNewTotalAmountVar extends DSLCostPolicyVar("newTotalAmount")
+case object NewTotalAmountInput extends ChargingInput("newTotalAmount")
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the time delta between two
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the time delta between two
  * consecutive resource events of the same type (same `resource` and `instanceId`). Time is measured in milliseconds.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLTimeDeltaVar extends DSLCostPolicyVar("timeDelta") {
-  override def isDirectlyRelatedToPreviousEvent = true
-  override def isDirectlyRelatedToCurrentEvent = true
-}
+case object TimeDeltaInput extends ChargingInput("timeDelta", true, true)
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the `value` of the previous
- * [[gr.grnet.aquarium.logic.events.ResourceEvent]].
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the `value` of the previous
+ * [[gr.grnet.aquarium.event.model.resource.ResourceEventModel]].
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLPreviousValueVar extends DSLCostPolicyVar("previousValue") {
-  override def isDirectlyRelatedToPreviousEvent = true
-}
+case object PreviousValueInput extends ChargingInput("previousValue", true, false)
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the `value` of the current
- * [[gr.grnet.aquarium.logic.events.ResourceEvent]].
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the `value` of the current
+ * [[gr.grnet.aquarium.event.model.resource.ResourceEventModel]].
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLCurrentValueVar extends DSLCostPolicyVar("currentValue") {
-  override def isDirectlyRelatedToCurrentEvent = true
-}
+case object CurrentValueInput extends ChargingInput("currentValue", false, true)
 
 /**
- * The type of [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar]] that holds the unit price as
- * given in a [[gr.grnet.aquarium.logic.accounting.dsl.DSLPriceList]].
- *
+ * The type of [[gr.grnet.aquarium.charging.ChargingInput]] that holds the unit price.
+ * 
+ * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case object DSLUnitPriceVar extends DSLCostPolicyVar("unitPrice")
+case object UnitPriceInput extends ChargingInput("unitPrice")
+
+case object DetailsInput extends ChargingInput("details")
+
+
+
+
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.computation
-package state
-package parts
+package gr.grnet.aquarium.charging
 
-import gr.grnet.aquarium.util.date.MutableDateCalc
-import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
+import gr.grnet.aquarium.AquariumException
 
 /**
- * Represents an agreement valid for a specific amount of time. By convention,
- * if an agreement is currently valid, then the validTo field is equal to `Long.MaxValue`.
+ * Encapsulates the possible states that a resource with an
+ * [[gr.grnet.aquarium.charging.OnOffChargingBehavior]]
+ * can be.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case class AgreementHistoryItem(name: String, validFrom: Long, validTo: Long = Long.MaxValue) {
-  require(validTo > validFrom)
-  require(!name.isEmpty)
+sealed abstract class OnOffPolicyResourceState(val state: String) {
+  def isOn: Boolean = !isOff
+  def isOff: Boolean = !isOn
+}
 
-  def timeslot = Timeslot(validFrom, validTo)
+object OnResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.on) {
+  override def isOn = true
+}
 
-  override def toString =
-    "AgreementHistoryItem(%s, %s, %s)".
-      format(name, new MutableDateCalc(validFrom), new MutableDateCalc(validTo))
+object OffResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.off) {
+  override def isOff = true
 }
+
+object OnOffPolicyResourceState {
+  def apply(name: Any): OnOffPolicyResourceState = {
+    name match {
+      case x: String if (x.equalsIgnoreCase(OnOffPolicyResourceStateNames.on))  ⇒ OnResourceState
+      case y: String if (y.equalsIgnoreCase(OnOffPolicyResourceStateNames.off)) ⇒ OffResourceState
+      case a: Double if (a == 0) => OffResourceState
+      case b: Double if (b == 1) => OnResourceState
+      case i: Int if (i == 0) => OffResourceState
+      case j: Int if (j == 1) => OnResourceState
+      case _ => throw new AquariumException("Invalid OnOffPolicyResourceState %s".format(name))
+    }
+  }
+}
+
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.policy
+package gr.grnet.aquarium.charging
 
 /**
- * The implementation of how to charge a particular resource.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-case class ChargingBehavior(implementation: String)
+object OnOffPolicyResourceStateNames {
+  final val on  = "on"
+  final val off = "off"
+}
index ba7991a..16ceac4 100644 (file)
@@ -47,7 +47,6 @@ import gr.grnet.aquarium.util.date.MutableDateCalc
 case class Chargeslot(
     startMillis: Long,
     stopMillis: Long,
-    algorithmDefinition: String,
     unitPrice: Double,
     computedCredits: Option[Double] = None) {
 
@@ -60,7 +59,6 @@ case class Chargeslot(
     new MutableDateCalc(startMillis).toYYYYMMDDHHMMSSSSS,
     new MutableDateCalc(stopMillis).toYYYYMMDDHHMMSSSSS,
     unitPrice,
-    computedCredits,
-    algorithmDefinition
+    computedCredits
   )
 }
index 2edf20b..a7e4b3c 100644 (file)
@@ -42,8 +42,9 @@ import gr.grnet.aquarium.store.PolicyStore
 import gr.grnet.aquarium.util.date.MutableDateCalc
 import gr.grnet.aquarium.{AquariumInternalError, AquariumException}
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
-import gr.grnet.aquarium.logic.accounting.algorithm.CostPolicyAlgorithmCompiler
-import gr.grnet.aquarium.logic.accounting.dsl.{DSL, DSLResourcesMap, DSLPolicy, DSLResource, DSLPriceList, DSLAlgorithm, DSLAgreement, Timeslot, DSLUtils}
+import gr.grnet.aquarium.logic.accounting.algorithm.SimpleExecutableChargingBehaviorAlgorithm
+import gr.grnet.aquarium.logic.accounting.dsl.{Timeslot, DSLUtils}
+import gr.grnet.aquarium.policy.{EffectivePriceTable, PolicyModel, ResourceType, UserAgreementModel}
 
 /**
  * Methods for converting accounting events to wallet entries.
@@ -64,25 +65,19 @@ trait TimeslotComputations extends Loggable {
    * @return
    */
   protected
-  def splitTimeslotByPoliciesAndAgreements(referenceTimeslot: Timeslot,
-                                           policyTimeslots: List[Timeslot],
-                                           agreementTimeslots: List[Timeslot],
-                                           clogM: Maybe[ContextualLogger] = NoVal): List[Timeslot] = {
-
-    //    val clog = ContextualLogger.fromOther(clogM, logger, "splitTimeslotByPoliciesAndAgreements()")
-    //    clog.begin()
+  def splitTimeslotByPoliciesAndAgreements(
+      referenceTimeslot: Timeslot,
+      policyTimeslots: List[Timeslot],
+      agreementTimeslots: List[Timeslot],
+      clogM: Maybe[ContextualLogger] = NoVal
+  ): List[Timeslot] = {
 
     // Align policy and agreement validity timeslots to the referenceTimeslot
     val alignedPolicyTimeslots = referenceTimeslot.align(policyTimeslots)
     val alignedAgreementTimeslots = referenceTimeslot.align(agreementTimeslots)
 
-    //    clog.debug("referenceTimeslot = %s", referenceTimeslot)
-    //    clog.debugSeq("alignedPolicyTimeslots", alignedPolicyTimeslots, 0)
-    //    clog.debugSeq("alignedAgreementTimeslots", alignedAgreementTimeslots, 0)
-
     val result = alignTimeslots(alignedPolicyTimeslots, alignedAgreementTimeslots)
-    //    clog.debugSeq("result", result, 1)
-    //    clog.end()
+
     result
   }
 
@@ -92,53 +87,43 @@ trait TimeslotComputations extends Loggable {
    *
    */
   protected
-  def resolveEffectiveAlgorithmsAndPriceLists(alignedTimeslot: Timeslot,
-                                              agreement: DSLAgreement,
-                                              clogOpt: Option[ContextualLogger] = None):
-  (Map[Timeslot, DSLAlgorithm], Map[Timeslot, DSLPriceList]) = {
+  def resolveEffectiveUnitPrices(
+      alignedTimeslot: Timeslot,
+      policy: PolicyModel,
+      agreement: UserAgreementModel,
+      resourceType: ResourceType,
+      clogOpt: Option[ContextualLogger] = None
+  ): SortedMap[Timeslot, Double] = {
 
-    val clog = ContextualLogger.fromOther(clogOpt, logger, "resolveEffectiveAlgorithmsAndPriceLists()")
+    val clog = ContextualLogger.fromOther(clogOpt, logger, "resolveEffectiveUnitPrices()")
 
     // Note that most of the code is taken from calcChangeChunks()
-    val alg = dslUtils.resolveEffectiveAlgorithmsForTimeslot(alignedTimeslot, agreement)
-    val pri = dslUtils.resolveEffectivePricelistsForTimeslot(alignedTimeslot, agreement)
-    val chargeChunks = splitChargeChunks(alg, pri)
-    val algorithmByTimeslot = chargeChunks._1
-    val pricelistByTimeslot = chargeChunks._2
-
-    assert(algorithmByTimeslot.size == pricelistByTimeslot.size)
-
-    (algorithmByTimeslot, pricelistByTimeslot)
+    dslUtils.resolveEffectiveUnitPricesForTimeslot(alignedTimeslot, policy, agreement, resourceType)
   }
 
   protected
-  def computeInitialChargeslots(referenceTimeslot: Timeslot,
-                                dslResource: DSLResource,
-                                policiesByTimeslot: Map[Timeslot, DSLPolicy],
-                                agreementNamesByTimeslot: Map[Timeslot, String],
-                                clogOpt: Option[ContextualLogger] = None): List[Chargeslot] = {
+  def computeInitialChargeslots(
+      referenceTimeslot: Timeslot,
+      resourceType: ResourceType,
+      policyByTimeslot: SortedMap[Timeslot, PolicyModel],
+      agreementByTimeslot: SortedMap[Timeslot, UserAgreementModel],
+      clogOpt: Option[ContextualLogger] = None
+  ): List[Chargeslot] = {
 
     val clog = ContextualLogger.fromOther(clogOpt, logger, "computeInitialChargeslots()")
-    //    clog.begin()
-
-    val policyTimeslots = policiesByTimeslot.keySet
-    val agreementTimeslots = agreementNamesByTimeslot.keySet
 
-    //    clog.debugMap("policiesByTimeslot", policiesByTimeslot, 1)
-    //    clog.debugMap("agreementNamesByTimeslot", agreementNamesByTimeslot, 1)
+    val policyTimeslots = policyByTimeslot.keySet
+    val agreementTimeslots = agreementByTimeslot.keySet
 
-    def getPolicy(ts: Timeslot): DSLPolicy = {
-      policiesByTimeslot.find(_._1.contains(ts)).get._2
+    def getPolicyWithin(ts: Timeslot): PolicyModel = {
+      policyByTimeslot.find(_._1.contains(ts)).get._2
     }
-    def getAgreementName(ts: Timeslot): String = {
-      agreementNamesByTimeslot.find(_._1.contains(ts)).get._2
+    def getAgreementWithin(ts: Timeslot): UserAgreementModel = {
+      agreementByTimeslot.find(_._1.contains(ts)).get._2
     }
 
     // 1. Round ONE: split time according to overlapping policies and agreements.
-    //    clog.begin("ROUND 1")
     val alignedTimeslots = splitTimeslotByPoliciesAndAgreements(referenceTimeslot, policyTimeslots.toList, agreementTimeslots.toList, Just(clog))
-    //    clog.debugSeq("alignedTimeslots", alignedTimeslots, 1)
-    //    clog.end("ROUND 1")
 
     // 2. Round TWO: Use the aligned timeslots of Round ONE to produce even more
     //    fine-grained timeslots according to applicable algorithms.
@@ -147,81 +132,31 @@ trait TimeslotComputations extends Loggable {
     val allChargeslots = for {
       alignedTimeslot <- alignedTimeslots
     } yield {
-      //      val alignedTimeslotMsg = "alignedTimeslot = %s".format(alignedTimeslot)
-      //      clog.begin(alignedTimeslotMsg)
-
-      val dslPolicy = getPolicy(alignedTimeslot)
+      val policy = getPolicyWithin(alignedTimeslot)
       //      clog.debug("dslPolicy = %s", dslPolicy)
-      val agreementName = getAgreementName(alignedTimeslot)
-      //      clog.debug("agreementName = %s", agreementName)
-      val agreementOpt = dslPolicy.findAgreement(agreementName)
-      //      clog.debug("agreementOpt = %s", agreementOpt)
-
-      agreementOpt match {
-        case None ⇒
-          val errMsg = "Unknown agreement %s during %s".format(agreementName, alignedTimeslot)
-          clog.error("%s", errMsg)
-          throw new AquariumException(errMsg)
-
-        case Some(agreement) ⇒
-          // TODO: Factor this out, just like we did with:
-          // TODO:  val alignedTimeslots = splitTimeslotByPoliciesAndAgreements
-          // Note that most of the code is already taken from calcChangeChunks()
-          val r = resolveEffectiveAlgorithmsAndPriceLists(alignedTimeslot, agreement, Some(clog))
-          val algorithmByTimeslot: Map[Timeslot, DSLAlgorithm] = r._1
-          val pricelistByTimeslot: Map[Timeslot, DSLPriceList] = r._2
-
-          // Now, the timeslots must be the same
-          val finegrainedTimeslots = algorithmByTimeslot.keySet
-
-          val chargeslots = for {
-            finegrainedTimeslot <- finegrainedTimeslots
-          } yield {
-            //            val finegrainedTimeslotMsg = "finegrainedTimeslot = %s".format(finegrainedTimeslot)
-            //            clog.begin(finegrainedTimeslotMsg)
-
-            val dslAlgorithm = algorithmByTimeslot(finegrainedTimeslot) // TODO: is this correct?
-            //            clog.debug("dslAlgorithm = %s", dslAlgorithm)
-            //            clog.debugMap("dslAlgorithm.algorithms", dslAlgorithm.algorithms, 1)
-            val dslPricelist = pricelistByTimeslot(finegrainedTimeslot) // TODO: is this correct?
-            //            clog.debug("dslPricelist = %s", dslPricelist)
-            //            clog.debug("dslResource = %s", dslResource)
-            val algorithmDefOpt = dslAlgorithm.algorithms.get(dslResource)
-            //            clog.debug("algorithmDefOpt = %s", algorithmDefOpt)
-            val priceUnitOpt = dslPricelist.prices.get(dslResource)
-            //            clog.debug("priceUnitOpt = %s", priceUnitOpt)
-
-            val chargeslot = (algorithmDefOpt, priceUnitOpt) match {
-              case (None, None) ⇒
-                throw new AquariumException(
-                  "Unknown algorithm and price unit for resource %s during %s".
-                    format(dslResource, finegrainedTimeslot))
-              case (None, _) ⇒
-                throw new AquariumException(
-                  "Unknown algorithm for resource %s during %s".
-                    format(dslResource, finegrainedTimeslot))
-              case (_, None) ⇒
-                throw new AquariumException(
-                  "Unknown price unit for resource %s during %s".
-                    format(dslResource, finegrainedTimeslot))
-              case (Some(algorithmDefinition), Some(priceUnit)) ⇒
-                Chargeslot(finegrainedTimeslot.from.getTime, finegrainedTimeslot.to.getTime, algorithmDefinition, priceUnit)
-            }
-
-            //            clog.end(finegrainedTimeslotMsg)
-            chargeslot
-          }
-
-          //          clog.end(alignedTimeslotMsg)
-          chargeslots.toList
+      val userAgreement = getAgreementWithin(alignedTimeslot)
+
+      // TODO: Factor this out, just like we did with:
+      // TODO:  val alignedTimeslots = splitTimeslotByPoliciesAndAgreements
+      // Note that most of the code is already taken from calcChangeChunks()
+      val unitPriceByTimeslot = resolveEffectiveUnitPrices(alignedTimeslot, policy, userAgreement, resourceType, Some(clog))
+
+      // Now, the timeslots must be the same
+      val finegrainedTimeslots = unitPriceByTimeslot.keySet
+
+      val chargeslots = for (finegrainedTimeslot ← finegrainedTimeslots) yield {
+        Chargeslot(
+          finegrainedTimeslot.from.getTime,
+          finegrainedTimeslot.to.getTime,
+          unitPriceByTimeslot(finegrainedTimeslot)
+        )
       }
-    }
-    //    clog.end("ROUND 2")
 
+      chargeslots.toList
+    }
 
     val result = allChargeslots.flatten
-    //    clog.debugSeq("result", allChargeslots, 1)
-    //    clog.end()
+
     result
   }
 
@@ -235,10 +170,9 @@ trait TimeslotComputations extends Loggable {
       oldCredits: Double,
       oldTotalAmount: Double,
       newTotalAmount: Double,
-      dslResource: DSLResource,
-      defaultResourceMap: DSLResourcesMap,
-      agreementNamesByTimeslot: SortedMap[Timeslot, String],
-      algorithmCompiler: CostPolicyAlgorithmCompiler,
+      resourceType: ResourceType,
+      defaultResourceTypesMap: Map[String, ResourceType],
+      agreementByTimeslot: SortedMap[Timeslot, UserAgreementModel],
       policyStore: PolicyStore,
       clogOpt: Option[ContextualLogger] = None
   ): (Timeslot, List[Chargeslot]) = {
@@ -248,53 +182,42 @@ trait TimeslotComputations extends Loggable {
 
     val occurredDate = currentResourceEvent.occurredDate
     val occurredMillis = currentResourceEvent.occurredMillis
-    val costPolicy = dslResource.costPolicy
+    val chargingBehavior = resourceType.chargingBehavior
 
-    val dsl = new DSL {}
-    val (referenceTimeslot, relevantPolicies, previousValue) = costPolicy.needsPreviousEventForCreditAndAmountCalculation match {
+    val (referenceTimeslot, relevantPolicies, previousValue) = chargingBehavior.needsPreviousEventForCreditAndAmountCalculation match {
       // We need a previous event
       case true ⇒
         previousResourceEventOpt match {
           // We have a previous event
           case Some(previousResourceEvent) ⇒
-            //            clog.debug("Have previous event")
-            //            clog.debug("previousValue = %s", previousResourceEvent.value)
-
             val referenceTimeslot = Timeslot(previousResourceEvent.occurredDate, occurredDate)
-            //            clog.debug("referenceTimeslot = %s".format(referenceTimeslot))
-
             // all policies within the interval from previous to current resource event
             //            clog.debug("Calling policyStore.loadAndSortPoliciesWithin(%s)", referenceTimeslot)
-            val relevantPolicies = policyStore.loadAndSortPoliciesWithin(referenceTimeslot.from.getTime, referenceTimeslot.to.getTime, dsl)
-            //            clog.debugMap("==> relevantPolicies", relevantPolicies, 0)
+            // TODO: store policies in mem?
+            val relevantPolicies = policyStore.loadAndSortPoliciesWithin(referenceTimeslot.from.getTime, referenceTimeslot.to.getTime)
 
             (referenceTimeslot, relevantPolicies, previousResourceEvent.value)
 
           // We do not have a previous event
           case None ⇒
-            throw new AquariumException(
-              "Unable to charge. No previous event given for %s".
-                format(currentResourceEvent.toDebugString))
+            throw new AquariumInternalError(
+              "Unable to charge. No previous event given for %s".format(currentResourceEvent.toDebugString))
         }
 
       // We do not need a previous event
       case false ⇒
         // ... so we cannot compute timedelta from a previous event, there is just one chargeslot
         // referring to (almost) an instant in time
-        //        clog.debug("DO NOT have previous event")
-        val previousValue = costPolicy.getResourceInstanceUndefinedAmount
-        //        clog.debug("previousValue = costPolicy.getResourceInstanceUndefinedAmount = %s", previousValue)
+        val previousValue = chargingBehavior.getResourceInstanceUndefinedAmount
 
         val referenceTimeslot = Timeslot(new MutableDateCalc(occurredDate).goPreviousMilli.toDate, occurredDate)
-        //        clog.debug("referenceTimeslot = %s".format(referenceTimeslot))
 
-        //        clog.debug("Calling policyStore.loadValidPolicyEntryAt(%s)", new MutableDateCalc(occurredMillis))
-        val relevantPolicyOpt = policyStore.loadValidPolicyAt(occurredMillis, dsl)
-        //        clog.debug("  ==> relevantPolicyM = %s", relevantPolicyM)
+        // TODO: store policies in mem?
+        val relevantPolicyOpt: Option[PolicyModel] = policyStore.loadValidPolicyAt(occurredMillis)
 
         val relevantPolicies = relevantPolicyOpt match {
           case Some(relevantPolicy) ⇒
-            Map(referenceTimeslot -> relevantPolicy)
+            SortedMap(referenceTimeslot -> relevantPolicy)
 
           case None ⇒
             throw new AquariumInternalError("No relevant policy found for %s".format(referenceTimeslot))
@@ -305,16 +228,15 @@ trait TimeslotComputations extends Loggable {
 
     val initialChargeslots = computeInitialChargeslots(
       referenceTimeslot,
-      dslResource,
+      resourceType,
       relevantPolicies,
-      agreementNamesByTimeslot,
+      agreementByTimeslot,
       Some(clog)
     )
 
     val fullChargeslots = initialChargeslots.map {
-      case chargeslot@Chargeslot(startMillis, stopMillis, algorithmDefinition, unitPrice, _) ⇒
-        val execAlgorithm = algorithmCompiler.compile(algorithmDefinition)
-        val valueMap = costPolicy.makeValueMap(
+      case chargeslot@Chargeslot(startMillis, stopMillis, unitPrice, _) ⇒
+        val valueMap = chargingBehavior.makeValueMap(
           oldCredits,
           oldTotalAmount,
           newTotalAmount,
@@ -328,7 +250,7 @@ trait TimeslotComputations extends Loggable {
         clog.debugMap("valueMap", valueMap, 1)
 
         // This is it
-        val credits = execAlgorithm.apply(valueMap)
+        val credits = SimpleExecutableChargingBehaviorAlgorithm.apply(valueMap)
         chargeslot.copyWithCredits(credits)
     }
 
@@ -338,40 +260,6 @@ trait TimeslotComputations extends Loggable {
   }
 
   /**
-   * Align charge timeslots between algorithms and pricelists. As algorithm
-   * and pricelists can have different effectivity periods, this method
-   * examines them and splits them as necessary.
-   */
-  private[computation] def splitChargeChunks(alg: SortedMap[Timeslot, DSLAlgorithm],
-                                       price: SortedMap[Timeslot, DSLPriceList]):
-  (Map[Timeslot, DSLAlgorithm], Map[Timeslot, DSLPriceList]) = {
-
-    val zipped = alg.keySet.zip(price.keySet)
-
-    zipped.find(p => !p._1.equals(p._2)) match {
-      case None => (alg, price)
-      case Some(x) =>
-        val algTimeslot = x._1
-        val priTimeslot = x._2
-
-        assert(algTimeslot.from == priTimeslot.from)
-
-        if(algTimeslot.endsAfter(priTimeslot)) {
-          val slices = algTimeslot.slice(priTimeslot.to)
-          val algo = alg.get(algTimeslot).get
-          val newalg = alg - algTimeslot ++ Map(slices.apply(0) -> algo) ++ Map(slices.apply(1) -> algo)
-          splitChargeChunks(newalg, price)
-        }
-        else {
-          val slices = priTimeslot.slice(priTimeslot.to)
-          val pl = price.get(priTimeslot).get
-          val newPrice = price - priTimeslot ++ Map(slices.apply(0) -> pl) ++ Map(slices.apply(1) -> pl)
-          splitChargeChunks(alg, newPrice)
-        }
-    }
-  }
-
-  /**
    * Given two lists of timeslots, produce a list which contains the
    * set of timeslot slices, as those are defined by
    * timeslot overlaps.
index 0ee314d..e587959 100644 (file)
@@ -38,15 +38,13 @@ package gr.grnet.aquarium.computation
 import gr.grnet.aquarium.util.{ContextualLogger, Loggable}
 import gr.grnet.aquarium.util.shortClassNameOf
 import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
-import gr.grnet.aquarium.logic.accounting.dsl.DSLResourcesMap
 import gr.grnet.aquarium.computation.state.parts._
 import gr.grnet.aquarium.event.model.NewWalletEntry
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
-import gr.grnet.aquarium.{AquariumAwareSkeleton, Aquarium, AquariumAware, AquariumInternalError}
+import gr.grnet.aquarium.{AquariumAwareSkeleton, AquariumInternalError}
 import gr.grnet.aquarium.computation.reason.{MonthlyBillingCalculation, InitialUserStateSetup, UserStateChangeReason}
 import gr.grnet.aquarium.computation.state.{UserStateWorker, UserStateBootstrap, UserState}
-import gr.grnet.aquarium.service.event.AquariumCreatedEvent
-import com.google.common.eventbus.Subscribe
+import gr.grnet.aquarium.policy.ResourceType
 
 /**
  *
@@ -54,7 +52,6 @@ import com.google.common.eventbus.Subscribe
  */
 final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
   lazy val timeslotComputations  = new TimeslotComputations {} // FIXME
-  lazy val algorithmCompiler     = aquarium.algorithmCompiler
   lazy val policyStore           = aquarium.policyStore
   lazy val userStateStoreForRead = aquarium.userStateStore
   lazy val resourceEventStore    = aquarium.resourceEventStore
@@ -62,7 +59,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
   def findUserStateAtEndOfBillingMonth(
       userStateBootstrap: UserStateBootstrap,
       billingMonthInfo: BillingMonthInfo,
-      defaultResourcesMap: DSLResourcesMap,
+      defaultResourceTypesMap: Map[String, ResourceType],
       calculationReason: UserStateChangeReason,
       storeFunc: UserState ⇒ UserState,
       clogOpt: Option[ContextualLogger] = None
@@ -78,7 +75,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
       val userState0 = doFullMonthBilling(
         userStateBootstrap,
         billingMonthInfo,
-        defaultResourcesMap,
+        defaultResourceTypesMap,
         calculationReason,
         storeFunc,
         Some(clog)
@@ -194,7 +191,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
     val theValue = currentResourceEvent.value
     val theDetails = currentResourceEvent.details
 
-    val resourcesMap = userStateWorker.resourcesMap
+    val resourceTypesMap = userStateWorker.resourceTypesMap
 
     val currentResourceEventDebugInfo = rcDebugInfo(currentResourceEvent)
     clog.begin(currentResourceEventDebugInfo)
@@ -202,14 +199,13 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
     userStateWorker.debugTheMaps(clog)(rcDebugInfo)
 
     // Ignore the event if it is not billable (but still record it in the "previous" stuff).
-    // But to make this decision, first we need the resource definition (and its cost policy).
-    val dslResourceOpt = resourcesMap.findResource(theResource)
-    dslResourceOpt match {
-      // We have a resource (and thus a cost policy)
-      case Some(dslResource) ⇒
-        val costPolicy = dslResource.costPolicy
-        clog.debug("%s for %s", costPolicy, dslResource)
-        val isBillable = costPolicy.isBillableEvent(currentResourceEvent)
+    // But to make this decision, first we need the resource type (and its charging behavior).
+    resourceTypesMap.get(theResource) match {
+      // We have a resource type (and thus a charging behavior)
+      case Some(resourceType) ⇒
+        val chargingBehavior = resourceType.chargingBehavior
+        clog.debug("%s for %s", chargingBehavior, resourceType)
+        val isBillable = chargingBehavior.isBillableEvent(currentResourceEvent)
         if(!isBillable) {
           // The resource event is not billable
           clog.debug("Ignoring not billable %s", currentResourceEventDebugInfo)
@@ -221,7 +217,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
           clog.debug("PreviousM %s", previousResourceEventOpt0.map(rcDebugInfo(_)))
 
           val havePreviousResourceEvent = previousResourceEventOpt0.isDefined
-          val needPreviousResourceEvent = costPolicy.needsPreviousEventForCreditAndAmountCalculation
+          val needPreviousResourceEvent = chargingBehavior.needsPreviousEventForCreditAndAmountCalculation
 
           val (proceed, previousResourceEventOpt1) = if(needPreviousResourceEvent && !havePreviousResourceEvent) {
             // This must be the first resource event of its kind, ever.
@@ -229,8 +225,8 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
 
             val actualFirstEvent = currentResourceEvent
 
-            if(costPolicy.isBillableFirstEvent(actualFirstEvent) &&
-              costPolicy.mustGenerateDummyFirstEvent) {
+            if(chargingBehavior.isBillableFirstEvent(actualFirstEvent) &&
+              chargingBehavior.mustGenerateDummyFirstEvent) {
 
               clog.debug("First event of its kind %s", currentResourceEventDebugInfo)
 
@@ -238,7 +234,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
               // Otherwise, the current event goes to the ignored list.
               // The dummy first is considered to exist at the beginning of the billing period
 
-              val dummyFirst = costPolicy.constructDummyFirstEventFor(currentResourceEvent, billingMonthInfo.monthStartMillis)
+              val dummyFirst = chargingBehavior.constructDummyFirstEventFor(currentResourceEvent, billingMonthInfo.monthStartMillis)
 
               clog.debug("Dummy first companion %s", rcDebugInfo(dummyFirst))
 
@@ -254,18 +250,18 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
           }
 
           if(proceed) {
-            val defaultInitialAmount = costPolicy.getResourceInstanceInitialAmount
+            val defaultInitialAmount = chargingBehavior.getResourceInstanceInitialAmount
             val oldAmount = _workingUserState.getResourceInstanceAmount(theResource, theInstanceId, defaultInitialAmount)
             val oldCredits = _workingUserState.totalCredits
 
             // A. Compute new resource instance accumulating amount
-            val newAccumulatingAmount = costPolicy.computeNewAccumulatingAmount(oldAmount, theValue, theDetails)
+            val newAccumulatingAmount = chargingBehavior.computeNewAccumulatingAmount(oldAmount, theValue, theDetails)
 
             clog.debug("theValue = %s, oldAmount = %s, newAmount = %s, oldCredits = %s", theValue, oldAmount, newAccumulatingAmount, oldCredits)
 
             // B. Compute new wallet entries
             clog.debug("agreementsSnapshot = %s", _workingUserState.agreementHistory)
-            val alltimeAgreements = _workingUserState.agreementHistory.agreementNamesByTimeslot
+            val alltimeAgreements = _workingUserState.agreementHistory.agreementsByTimeslot
 
             //              clog.debug("Computing full chargeslots")
             val (referenceTimeslot, fullChargeslots) = timeslotComputations.computeFullChargeslots(
@@ -274,10 +270,9 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
               oldCredits,
               oldAmount,
               newAccumulatingAmount,
-              dslResource,
-              resourcesMap,
+              resourceType,
+              resourceTypesMap,
               alltimeAgreements,
-              algorithmCompiler,
               policyStore,
               Some(clog)
             )
@@ -307,7 +302,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
               else
                 List(currentResourceEvent),
               fullChargeslots,
-              dslResource,
+              resourceType,
               currentResourceEvent.isSynthetic
             )
             clog.debug("%s = %s", shortClassNameOf(newWalletEntry), newWalletEntry)
@@ -370,7 +365,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
   def doFullMonthBilling(
       userStateBootstrap: UserStateBootstrap,
       billingMonthInfo: BillingMonthInfo,
-      defaultResourcesMap: DSLResourcesMap,
+      defaultResourceTypesMap: Map[String, ResourceType],
       calculationReason: UserStateChangeReason,
       storeFunc: UserState ⇒ UserState,
       clogOpt: Option[ContextualLogger] = None
@@ -380,7 +375,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
       billingMonthInfo,
       billingMonthInfo.monthStopMillis,
       userStateBootstrap,
-      defaultResourcesMap,
+      defaultResourceTypesMap,
       calculationReason,
       storeFunc,
       clogOpt
@@ -397,7 +392,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
        */
       billingEndTimeMillis: Long,
       userStateBootstrap: UserStateBootstrap,
-      defaultResourcesMap: DSLResourcesMap,
+      defaultResourceTypesMap: Map[String, ResourceType],
       calculationReason: UserStateChangeReason,
       storeFunc: UserState ⇒ UserState,
       clogOpt: Option[ContextualLogger] = None
@@ -420,7 +415,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
     val previousBillingMonthUserState = findUserStateAtEndOfBillingMonth(
       userStateBootstrap,
       previousBillingMonthInfo,
-      defaultResourcesMap,
+      defaultResourceTypesMap,
       calculationReason,
       storeFunc,
       clogSome
@@ -437,7 +432,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
     // NOTE: The calculation reason is not the one we get from the previous user state but the one our caller specifies
     var _workingUserState = startingUserState.newWithChangeReason(calculationReason)
 
-    val userStateWorker = UserStateWorker.fromUserState(_workingUserState, defaultResourcesMap)
+    val userStateWorker = UserStateWorker.fromUserState(_workingUserState, defaultResourceTypesMap)
 
     userStateWorker.debugTheMaps(clog)(rcDebugInfo)
 
@@ -491,7 +486,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable {
         LatestResourceEventsWorker.fromList(specialEvents),
         ImplicitlyIssuedResourceEventsWorker.Empty,
         IgnoredFirstResourceEventsWorker.Empty,
-        userStateWorker.resourcesMap
+        userStateWorker.resourceTypesMap
       )
 
       _workingUserState = processResourceEvents(
index 8ffe17c..f9bfb17 100644 (file)
@@ -38,12 +38,12 @@ package gr.grnet.aquarium.computation.state
 import gr.grnet.aquarium.converter.{JsonTextFormat, StdConverters}
 import gr.grnet.aquarium.event.model.NewWalletEntry
 import gr.grnet.aquarium.util.json.JsonSupport
-import gr.grnet.aquarium.logic.accounting.dsl.DSLAgreement
 import gr.grnet.aquarium.computation.reason.{NoSpecificChangeReason, UserStateChangeReason, InitialUserStateSetup}
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
 import gr.grnet.aquarium.computation.BillingMonthInfo
 import gr.grnet.aquarium.computation.parts.RoleHistory
 import gr.grnet.aquarium.computation.state.parts.{OwnedResourcesMap, ResourceInstanceSnapshot, OwnedResourcesSnapshot, AgreementHistory, ImplicitlyIssuedResourceEventsSnapshot, LatestResourceEventsSnapshot}
+import gr.grnet.aquarium.policy.UserAgreementModel
 
 /**
  * A comprehensive representation of the User's state.
@@ -162,7 +162,7 @@ case class UserState(
   //
   //  def userCreationFormatedDate = new MutableDateCalc(userCreationMillis).toString
 
-  def findDSLAgreementForTime(at: Long): Option[DSLAgreement] = {
+  def findDSLAgreementForTime(at: Long): Option[UserAgreementModel] = {
     agreementHistory.findForTime(at)
   }
 
@@ -256,8 +256,7 @@ object UserState {
       userCreationMillis: Long,
       occurredMillis: Long,
       totalCredits: Double,
-      initialRole: String,
-      initialAgreement: String,
+      initialAgreement: UserAgreementModel,
       calculationReason: UserStateChangeReason = InitialUserStateSetup(None)
   ) = {
 
@@ -272,8 +271,8 @@ object UserState {
       LatestResourceEventsSnapshot.Empty,
       0L,
       totalCredits,
-      RoleHistory.initial(initialRole, userCreationMillis),
-      AgreementHistory.initial(initialAgreement, userCreationMillis),
+      RoleHistory.initial(initialAgreement.role, userCreationMillis),
+      AgreementHistory.initial(initialAgreement),
       OwnedResourcesSnapshot.Empty,
       Nil,
       occurredMillis,
@@ -292,7 +291,6 @@ object UserState {
       usb.userCreationMillis,
       occurredMillis,
       usb.initialCredits,
-      usb.initialRole,
       usb.initialAgreement,
       calculationReason
     )
index 244470c..7401e91 100644 (file)
@@ -35,6 +35,8 @@
 
 package gr.grnet.aquarium.computation.state
 
+import gr.grnet.aquarium.policy.UserAgreementModel
+
 /**
  * This is used to bootstrap the [[gr.grnet.aquarium.computation.state.UserState]].
  *
@@ -44,7 +46,6 @@ package gr.grnet.aquarium.computation.state
 case class UserStateBootstrap(
     userID:             String,
     userCreationMillis: Long,
-    initialRole:        String,
-    initialAgreement:   String,
+    initialAgreement:   UserAgreementModel,
     initialCredits:     Double
 )
index 6be9f39..bb0692f 100644 (file)
@@ -37,10 +37,10 @@ package gr.grnet.aquarium.computation
 package state
 
 import scala.collection.mutable
-import gr.grnet.aquarium.logic.accounting.dsl.DSLResourcesMap
 import gr.grnet.aquarium.util.ContextualLogger
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
 import gr.grnet.aquarium.computation.state.parts.{IgnoredFirstResourceEventsWorker, ImplicitlyIssuedResourceEventsWorker, LatestResourceEventsWorker}
+import gr.grnet.aquarium.policy.ResourceType
 
 /**
  * A helper object holding intermediate state/results during resource event processing.
@@ -66,7 +66,7 @@ case class UserStateWorker(
      * The resource events that were first (and unused) of their kind.
      */
     ignoredFirstResourceEvents: IgnoredFirstResourceEventsWorker,
-    resourcesMap: DSLResourcesMap
+    resourceTypesMap: Map[String, ResourceType]
 ) {
 
   /**
@@ -141,7 +141,7 @@ case class UserStateWorker(
    * end events along with those implicitly issued events. Before returning, remove the events that generated the
    * implicit ends from the internal state of this instance.
    *
-   * @see [[gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicy]]
+   * @see [[gr.grnet.aquarium.charging.ChargingBehavior]]
    */
   def findAndRemoveGeneratorsOfImplicitEndEvents(
       /**
@@ -158,12 +158,12 @@ case class UserStateWorker(
       val resourceEvents = map.valuesIterator
       for {
         resourceEvent ← resourceEvents
-        dslResource ← resourcesMap.findResource(resourceEvent.safeResource)
-        costPolicy = dslResource.costPolicy
+        resourceType ← resourceTypesMap.get(resourceEvent.safeResource)
+        chargingBehavior = resourceType.chargingBehavior
       } {
-        if(costPolicy.supportsImplicitEvents) {
-          if(costPolicy.mustConstructImplicitEndEventFor(resourceEvent)) {
-            val implicitEnd = costPolicy.constructImplicitEndEventFor(resourceEvent, newOccuredMillis)
+        if(chargingBehavior.supportsImplicitEvents) {
+          if(chargingBehavior.mustConstructImplicitEndEventFor(resourceEvent)) {
+            val implicitEnd = chargingBehavior.constructImplicitEndEventFor(resourceEvent, newOccuredMillis)
 
             if(!checkSet.contains(resourceEvent)) {
               checkSet.add(resourceEvent)
@@ -185,13 +185,13 @@ case class UserStateWorker(
 }
 
 object UserStateWorker {
-  def fromUserState(userState: UserState, resourcesMap: DSLResourcesMap): UserStateWorker = {
+  def fromUserState(userState: UserState, resourceTypesMap: Map[String, ResourceType]): UserStateWorker = {
     UserStateWorker(
       userState.userID,
       userState.latestResourceEventsSnapshot.toMutableWorker,
       userState.implicitlyIssuedSnapshot.toMutableWorker,
       IgnoredFirstResourceEventsWorker.Empty,
-      resourcesMap
+      resourceTypesMap
     )
   }
 }
index c08ff65..befb03c 100644 (file)
@@ -37,11 +37,9 @@ package gr.grnet.aquarium.computation
 package state
 package parts
 
-import java.util.Date
-
-import gr.grnet.aquarium.logic.accounting.dsl.{DSLAgreement, Timeslot}
-import gr.grnet.aquarium.logic.accounting.Policy
+import gr.grnet.aquarium.logic.accounting.dsl.{Timeslot}
 import scala.collection.immutable.{SortedMap, TreeMap}
+import gr.grnet.aquarium.policy.UserAgreementModel
 
 /**
  * User agreement parts that will be part of UserState.
@@ -50,10 +48,10 @@ import scala.collection.immutable.{SortedMap, TreeMap}
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-case class AgreementHistory(agreements: List[AgreementHistoryItem]) {
+case class AgreementHistory(agreements: List[UserAgreementModel]) {
   ensureNoGaps(agreements.sortWith((a,b) => if (b.validFrom > a.validFrom) true else false))
 
-  def ensureNoGaps(agreements: List[AgreementHistoryItem]): Unit = agreements match {
+  def ensureNoGaps(agreements: List[UserAgreementModel]): Unit = agreements match {
     case ha :: (t @ (hb :: tail)) =>
       assert(ha.validTo - hb.validFrom == 1);
       ensureNoGaps(t)
@@ -62,58 +60,37 @@ case class AgreementHistory(agreements: List[AgreementHistoryItem]) {
     case Nil => ()
   }
 
-  def agreementNamesByTimeslot: SortedMap[Timeslot, String] = {
-    TreeMap(agreements.map(ag ⇒ (ag.timeslot, ag.name)): _*)
-  }
-
-  def agreementsByTimeslot: SortedMap[Timeslot, AgreementHistoryItem] = {
+  def agreementsByTimeslot: SortedMap[Timeslot, UserAgreementModel] = {
     TreeMap(agreements.map(ag ⇒ (ag.timeslot, ag)): _*)
   }
 
   /**
    * Get the user agreement at the specified timestamp
    */
-  def findForTime(at: Long): Option[DSLAgreement] = {
+  def findForTime(at: Long): Option[UserAgreementModel] = {
     // FIXME: Refactor and do not make this static call to Policy
-    agreements.find{ x => x.validFrom < at && x.validTo > at} match {
-      case Some(x) => Policy.policy(new Date(at)).findAgreement(x.name)
-      case None => None
-    }
+    None
   }
 
   /**
    * Returns the first, chronologically, agreement.
    */
-  def firstAgreement: Option[AgreementHistoryItem] = {
+  def firstAgreement: Option[UserAgreementModel] = {
     agreementsByTimeslot.valuesIterator.toList.lastOption
   }
 
   /**
-   * Returns the name of the first, chronologically, agreement.
-   */
-  def firstAgreementName: Option[String] = {
-    agreementNamesByTimeslot.valuesIterator.toList.lastOption
-  }
-
-  /**
    * Returns the last, chronologically, agreement.
    */
-  def lastAgreement: Option[AgreementHistoryItem] = {
+  def lastAgreement: Option[UserAgreementModel] = {
     agreementsByTimeslot.valuesIterator.toList.headOption
   }
-
-  /**
-   * Returns the name of the last, chronologically, agreement.
-   */
-  def lastAgreementName: Option[String] = {
-    agreementNamesByTimeslot.valuesIterator.toList.headOption
-  }
 }
 
 object AgreementHistory {
   final val Empty = AgreementHistory(Nil)
 
-  def initial(agreement: String, validFrom: Long): AgreementHistory ={
-    AgreementHistory(AgreementHistoryItem(agreement, validFrom) :: Nil)
+  def initial(userAgreement: UserAgreementModel): AgreementHistory ={
+    AgreementHistory(userAgreement :: Nil)
   }
 }
index 12a606e..bb9b379 100644 (file)
@@ -37,9 +37,10 @@ package gr.grnet.aquarium.event.model
 
 import gr.grnet.aquarium.computation.Chargeslot
 import gr.grnet.aquarium.util.date.MutableDateCalc
-import gr.grnet.aquarium.logic.accounting.dsl.{Timeslot, DSLResource}
+import gr.grnet.aquarium.logic.accounting.dsl.{Timeslot}
 import resource.ResourceEventModel
 import gr.grnet.aquarium.converter.{JsonTextFormat, StdConverters}
+import gr.grnet.aquarium.policy.ResourceType
 
 /**
  * The following equation must hold: `newTotalCredits = oldTotalCredits + entryCredits`.
@@ -67,7 +68,7 @@ case class NewWalletEntry(userId: String,
                           billingMonth: Int,
                           resourceEvents: List[ResourceEventModel], // current is at the head
                           chargeslots: List[Chargeslot],
-                          resourceDef: DSLResource,
+                          resourceDef: ResourceType,
                           isSynthetic: Boolean) {
 
   def currentResourceEvent = resourceEvents.head
diff --git a/src/main/scala/gr/grnet/aquarium/event/model/PolicyEntry.scala b/src/main/scala/gr/grnet/aquarium/event/model/PolicyEntry.scala
deleted file mode 100644 (file)
index 8ea7401..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.event.model
-
-import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
-import java.util.Date
-import gr.grnet.aquarium.converter.{JsonTextFormat, StdConverters}
-
-/**
- * Store entry for serialized policy parts.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-case class PolicyEntry(
-                        id: String, //SHA-1 of the provided policyYaml string
-                        occurredMillis: Long, //Time this event was stored
-                        receivedMillis: Long, //Does not make sense for local events -> not used
-                        policyYAML: String, //The serialized policy
-                        validFrom: Long, //The timestamp since when the policy is valid
-                        validTo: Long, //The timestamp until when the policy is valid
-                        eventVersion: String = "1.0",
-                        userID: String = "",
-                        details: Map[String, String] = Map()
-                        ) extends ExternalEventModel {
-
-  assert(if(validTo != -1) validTo > validFrom else validFrom > 0)
-
-  def validate = true
-
-  def withReceivedMillis(millis: Long) = copy(receivedMillis = millis)
-
-  def withDetails(newDetails: Map[String, String], newOccurredMillis: Long) =
-    this.copy(details = newDetails, occurredMillis = newOccurredMillis)
-
-  def fromToTimeslot = Timeslot(new Date(validFrom), new Date(validTo))
-}
-
-object PolicyEntry {
-
-  def fromJson(json: String): PolicyEntry = {
-    StdConverters.AllConverters.convertEx[PolicyEntry](JsonTextFormat(json))
-  }
-
-  object JsonNames {
-    final val _id = "_id"
-    final val id = "id"
-    final val occurredMillis = "occurredMillis"
-    final val receivedMillis = "receivedMillis"
-    final val policyYAML = "policyYAML"
-    final val validFrom = "validFrom"
-    final val validTo = "validTo"
-  }
-
-}
\ No newline at end of file
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/Policy.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/Policy.scala
deleted file mode 100644 (file)
index deee38f..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting
-
-import dsl.{Timeslot, DSLPolicy, DSL}
-import java.io.{InputStream, FileInputStream, File}
-import java.util.Date
-import gr.grnet.aquarium.util.Loggable
-import java.util.concurrent.atomic.AtomicReference
-import collection.immutable.{TreeMap, SortedMap}
-import gr.grnet.aquarium.{ResourceLocator, AquariumAwareSkeleton, AquariumException, Aquarium}
-import gr.grnet.aquarium.util.date.{MutableDateCalc, TimeHelpers}
-import com.ckkloverdos.maybe.{Failed, Just}
-
-/**
- * Searches for and loads the applicable accounting policy
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-object Policy extends DSL with Loggable with AquariumAwareSkeleton {
-
-  /* Pointer to the latest policy */
-  private[logic] lazy val policies = {
-    new AtomicReference[SortedMap[Timeslot, DSLPolicy]](reloadPolicies)
-  }
-
-  /* Pointer to the latest policy */
-  private lazy val currentPolicy = {new AtomicReference[DSLPolicy](latestPolicy)}
-
-  /* Aquarium to use for loading information about the policy store */
-  private var config: Aquarium = _
-
-  /**
-   * Get the latest defined policy.
-   */
-  def policy = currentPolicy.get
-
-  /**
-   * Get the policy that is valid at the specified time instance.
-   */
-  def policy(at: Date): DSLPolicy = {
-    policies.get.find {
-      a => (a._1.from.before(at) && a._1.to.after(at)) ||
-           (a._1.from.before(at) && a._1.to == Long.MaxValue)
-    } match {
-      case Some(x) => x._2
-      case None =>
-        throw new AquariumException("No valid policy for date: %s".format(new MutableDateCalc(at)))
-    }
-  }
-
-  /**
-   * Get the policies that are valid between the specified time instances,
-   * in a map whose keys are sorted by time.
-   */
-  def policies(from: Date, to: Date): SortedMap[Timeslot, DSLPolicy] = {
-    policies.get.filter {
-      a => a._1.from.before(from) &&
-           a._1.to.after(to)
-    }
-  }
-
-  /**
-   * Get the policies that are valid throughout the specified
-   * [[gr.grnet.aquarium.logic.accounting.dsl.Timeslot]]
-   */
-  def policies(t: Timeslot): SortedMap[Timeslot, DSLPolicy] = policies(t.from, t.to)
-
-  /**
-   * Load and parse a policy from file.
-   */
-  def loadPolicyFromFile(pol: File): DSLPolicy = {
-
-    val stream = pol.exists() match {
-      case true =>
-        logger.info("Using policy file %s".format(pol.getAbsolutePath))
-        new FileInputStream(pol)
-      case false =>
-        logger.warn(("Cannot find user configured policy file %s, " +
-          "looking for default policy").format(pol.getAbsolutePath))
-        getClass.getClassLoader.getResourceAsStream("policy.yaml") match {
-          case x: InputStream =>
-            logger.warn("Using default policy, this is problably not what you want")
-            x
-          case null =>
-            logger.error("No valid policy file found, Aquarium will fail")
-            null
-        }
-    }
-    parse(stream)
-  }
-
-  /**
-   * Trigger a policy update cycle.
-   */
-  def updatePolicies = synchronized {
-    //XXX: The following update should happen as one transaction
-    val tmpPol = reloadPolicies
-    currentPolicy.set(latestPolicy)
-    policies.set(tmpPol)
-  }
-
-  /**
-   * Find the latest policy in the list of policies.
-   */
-  private def latestPolicy =
-    policies.get.foldLeft((Timeslot(new Date(1), new Date(2)) -> DSLPolicy.emptyPolicy)) {
-      (acc, p) =>
-        if (acc._2 == DSLPolicy.emptyPolicy)
-          p
-        else if (p._1.after(acc._1))
-          p
-        else
-          acc
-    }._2
-
-  /**
-   * Set the configurator to use for loading policy stores. Should only
-   * used for unit testing.
-   */
-  def withConfigurator(config: Aquarium): Unit =
-    this.config = config
-
-  /**
-   * Check whether the policy definition file (in whichever path) is
-   * newer than the latest stored policy, reload and set it as current.
-   * This method has side-effects to this object's state.
-   */
-  private[logic] def reloadPolicies: SortedMap[Timeslot, DSLPolicy] =
-    if (config == null)
-      reloadPolicies(aquarium)
-    else
-      reloadPolicies(config)
-
-  private def reloadPolicies(config: Aquarium):
-  SortedMap[Timeslot, DSLPolicy] = {
-    //1. Load policies from db
-    val pol = config.policyStore.loadPolicyEntriesAfter(0)
-
-    //2. Check whether policy file has been updated
-    val latestPolicyChange = if (pol.isEmpty) 0 else pol.last.validFrom
-
-    val policyf = ResourceLocator.Resources.PolicyYAMLResource
-    var updated = false
-
-    if (policyf.exists) {
-        updated = true
-     } else {
-      logger.warn("User specified policy file %s does not exist, " +
-        "using stored policy information".format(policyf.url))
-    }
-
-    if (updated) {
-      val ts = TimeHelpers.nowMillis()
-      val parsedNewM = policyf.mapInputStream(parse).toMaybeEither
-      val parsedNew = parsedNewM match {
-        case Just(parsedNew) ⇒ parsedNew
-        case Failed(e)       ⇒ throw e
-      }
-      val newPolicy = parsedNew.toPolicyEntry
-
-      config.policyStore.findPolicyEntry(newPolicy.id) match {
-        case Some(x) =>
-          logger.warn("Policy file contents not modified")
-        case None =>
-          if (!pol.isEmpty) {
-            val toUpdate = pol.last.copy(validTo = ts - 1)
-            config.policyStore.updatePolicyEntry(toUpdate)
-            config.policyStore.storePolicyEntry(newPolicy)
-          } else {
-            config.policyStore.storePolicyEntry(newPolicy)
-          }
-      }
-    }
-
-    config.policyStore.loadPolicyEntriesAfter(0).foldLeft(new TreeMap[Timeslot, DSLPolicy]()){
-      (acc, p) =>
-        acc ++ Map(Timeslot(p.validFrom, p.validTo) -> parse(p.policyYAML))
-    }
-  }
-
-  Policy.policy
-}
\ No newline at end of file
index 85de5eb..3c880aa 100644 (file)
@@ -51,5 +51,5 @@ trait CostPolicyAlgorithmCompiler {
    * @param definition the textual representation of the algorithm
    * @return the executable form of the algorithm
    */
-  def compile(definition: String): ExecutableCostPolicyAlgorithm
+  def compile(definition: String): ExecutableChargingBehaviorAlgorithm
 }
 
 package gr.grnet.aquarium.logic.accounting.algorithm
 
+import gr.grnet.aquarium.charging.ChargingInput
 
-import com.ckkloverdos.maybe.Maybe
-import gr.grnet.aquarium.logic.accounting.dsl.DSLCostPolicyVar
 
 /**
  * An charging algorithm in executable form.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-trait ExecutableCostPolicyAlgorithm extends (Map[DSLCostPolicyVar, Any] ⇒ Double)
+trait ExecutableChargingBehaviorAlgorithm extends (Map[ChargingInput, Any] ⇒ Double)
index 1f4448a..19a8133 100644 (file)
@@ -51,7 +51,7 @@ object SimpleCostPolicyAlgorithmCompiler extends CostPolicyAlgorithmCompiler {
    * @param definition the textual representation of the algorithm
    * @return the executable form of the algorithm
    */
-  def compile(definition: String): ExecutableCostPolicyAlgorithm = {
-    SimpleExecutableCostPolicyAlgorithm
+  def compile(definition: String): ExecutableChargingBehaviorAlgorithm = {
+    SimpleExecutableChargingBehaviorAlgorithm
   }
 }
@@ -39,40 +39,41 @@ package gr.grnet.aquarium.logic.accounting.algorithm
 import com.ckkloverdos.maybe.Maybe
 import gr.grnet.aquarium.logic.accounting.dsl._
 import gr.grnet.aquarium.AquariumException
+import gr.grnet.aquarium.charging.{CurrentValueInput, TimeDeltaInput, OldTotalAmountInput, UnitPriceInput, ChargingBehaviorNames, ChargingBehaviorNameInput, ChargingInput}
 
 /**
  * An executable charging algorithm with some simple implementation.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-object SimpleExecutableCostPolicyAlgorithm extends ExecutableCostPolicyAlgorithm {
+object SimpleExecutableChargingBehaviorAlgorithm extends ExecutableChargingBehaviorAlgorithm {
 
   @inline private[this]
   def hrs(millis: Double) = millis / 1000 / 60 / 60
 
-  def apply(vars: Map[DSLCostPolicyVar, Any]): Double = {
-    vars.apply(DSLCostPolicyNameVar) match {
-      case DSLCostPolicyNames.continuous ⇒
-        val unitPrice = vars(DSLUnitPriceVar).asInstanceOf[Double]
-        val oldTotalAmount = vars(DSLOldTotalAmountVar).asInstanceOf[Double]
-        val timeDelta = vars(DSLTimeDeltaVar).asInstanceOf[Double]
+  def apply(vars: Map[ChargingInput, Any]): Double = {
+    vars.apply(ChargingBehaviorNameInput) match {
+      case ChargingBehaviorNames.continuous ⇒
+        val unitPrice = vars(UnitPriceInput).asInstanceOf[Double]
+        val oldTotalAmount = vars(OldTotalAmountInput).asInstanceOf[Double]
+        val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double]
 
         hrs(timeDelta) * oldTotalAmount * unitPrice
 
-      case DSLCostPolicyNames.discrete ⇒
-        val unitPrice = vars(DSLUnitPriceVar).asInstanceOf[Double]
-        val currentValue = vars(DSLCurrentValueVar).asInstanceOf[Double]
+      case ChargingBehaviorNames.discrete ⇒
+        val unitPrice = vars(UnitPriceInput).asInstanceOf[Double]
+        val currentValue = vars(CurrentValueInput).asInstanceOf[Double]
 
         currentValue * unitPrice
 
-      case DSLCostPolicyNames.onoff ⇒
-        val unitPrice = vars(DSLUnitPriceVar).asInstanceOf[Double]
-        val timeDelta = vars(DSLTimeDeltaVar).asInstanceOf[Double]
+      case ChargingBehaviorNames.onoff ⇒
+        val unitPrice = vars(UnitPriceInput).asInstanceOf[Double]
+        val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double]
 
         hrs(timeDelta) * unitPrice
 
-      case DSLCostPolicyNames.once ⇒
-        val currentValue = vars(DSLCurrentValueVar).asInstanceOf[Double]
+      case ChargingBehaviorNames.once ⇒
+        val currentValue = vars(CurrentValueInput).asInstanceOf[Double]
         currentValue
 
       case name ⇒
@@ -82,8 +83,8 @@ object SimpleExecutableCostPolicyAlgorithm extends ExecutableCostPolicyAlgorithm
 
   override def toString = "SimpleExecutableCostPolicyAlgorithm(%s)".format(
     Map(
-      DSLCostPolicyNames.continuous -> "hrs(timeDelta) * oldTotalAmount * unitPrice",
-      DSLCostPolicyNames.discrete   -> "currentValue * unitPrice",
-      DSLCostPolicyNames.onoff      -> "hrs(timeDelta) * unitPrice",
-      DSLCostPolicyNames.once       -> "currentValue"))
+      ChargingBehaviorNames.continuous -> "hrs(timeDelta) * oldTotalAmount * unitPrice",
+      ChargingBehaviorNames.discrete   -> "currentValue * unitPrice",
+      ChargingBehaviorNames.onoff      -> "hrs(timeDelta) * unitPrice",
+      ChargingBehaviorNames.once       -> "currentValue"))
 }
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala
deleted file mode 100644 (file)
index 8901cb5..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import scala.collection.JavaConversions._
-import com.kenai.crontabparser.impl.CronTabParserBridge
-import gr.grnet.aquarium.util.yaml._
-import java.util.Date
-import java.io.{ByteArrayInputStream, InputStreamReader, InputStream}
-
-/**
- * A parser for the Aquarium accounting DSL.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-trait DSL {
-
-  /**
-   * Parse an InputStream containing an Aquarium DSL.
-   */
-  @throws(classOf[DSLParseException])
-  def parse(input: InputStream) : DSLPolicy = {
-
-    val document = YAMLHelpers.loadYAML(new InputStreamReader(input))
-    val policy = document / (Vocabulary.aquariumpolicy)
-
-    val resources = parseResources(policy./(Vocabulary.resources).asInstanceOf[YAMLListNode])
-
-    val policies = parseAlgorithms(policy./(Vocabulary.algorithms).asInstanceOf[YAMLListNode],resources, List())
-
-    val pricelists = parsePriceLists(
-      policy./(Vocabulary.pricelists).asInstanceOf[YAMLListNode],
-      resources, List()
-    )
-
-    val creditplans = parseCreditPlans(
-      policy./(Vocabulary.creditplans).asInstanceOf[YAMLListNode], List()
-    )
-
-    val agreements = parseAgreements(
-      policy./(Vocabulary.agreements).asInstanceOf[YAMLListNode],
-      policies, pricelists, resources, creditplans, List()
-    )
-
-    DSLPolicy(policies, pricelists, resources, creditplans, agreements)
-  }
-
-  /**
-   * Parse an InputStream containing an Aquarium DSL.
-   */
-  @throws(classOf[DSLParseException])
-  def parse(yaml: String): DSLPolicy = parse(new ByteArrayInputStream(yaml.getBytes))
-
-  /** Parse resource declarations */
-  private def parseResources(resources: YAMLListNode): List[DSLResource] = {
-    if (resources.isEmpty)
-      return List()
-    resources.head match {
-      case x: YAMLMapNode => constructResource(x) :: parseResources(resources.tail)
-      case _ => throw new DSLParseException("Resource format unknown")
-    }
-  }
-
-  def constructResource(resource: YAMLMapNode): DSLResource = {
-    val name = resource / Vocabulary.name match {
-      case x: YAMLStringNode => x.string
-      case YAMLEmptyNode => throw new DSLParseException("Resource does not have a name")
-    }
-
-    val unit = resource / Vocabulary.unit match {
-      case x: YAMLStringNode => x.string
-      case YAMLEmptyNode => throw new DSLParseException("Resource %s does specify a unit".format(name))
-    }
-
-    val complex = resource / Vocabulary.complex match {
-      case x: YAMLBooleanNode => x.bool
-      case _ => throw new DSLParseException("Resource %s does specify a complex value".format(name))
-    }
-
-    val costpolicy = resource / Vocabulary.costpolicy match {
-      case x: YAMLStringNode => DSLCostPolicy(x.string)
-      case _ => throw new DSLParseException("Resource %s does specify a cost policy".format(name))
-    }
-
-    complex match {
-      case true =>
-        /*val field = resource / Vocabulary.descriminatorfield match {
-          case x: YAMLStringNode => x.string
-          case _ => throw new DSLParseException(("Resource %s is complex, " +
-            "but no descriminator field specified").format(name))
-        }*/
-        DSLComplexResource(name, unit, costpolicy)//, field)
-      case false =>
-        DSLSimpleResource(name, unit, costpolicy)
-    }
-  }
-
-  /** Parse top level algorithm declarations */
-  private def parseAlgorithms(algorithms: YAMLListNode,
-                    resources: List[DSLResource],
-                    results: List[DSLAlgorithm]): List[DSLAlgorithm] = {
-
-    algorithms.head match {
-      case YAMLEmptyNode => return List()
-      case _ =>
-    }
-
-    val superName = algorithms.head / Vocabulary.overrides
-    val algoTmpl = superName match {
-      case y: YAMLStringNode =>
-        results.find(p => p.name.equals(y.string)) match {
-          case Some(x) => x
-          case None => throw new DSLParseException("Cannot find super algorithm %s".format(superName))
-        }
-      case YAMLEmptyNode => DSLAlgorithm.emptyAlgorithm
-      case _ => throw new DSLParseException("Super algorithm name %s not a string".format())
-    }
-
-    val algorithm = constructAlgorithm(algorithms.head.asInstanceOf[YAMLMapNode],
-      algoTmpl, resources)
-
-    val tmpresults = algorithm :: results
-    algorithm :: parseAlgorithms(algorithms.tail, resources, tmpresults)
-  }
-
-  /** Construct an algorithm object from a yaml node*/
-  def constructAlgorithm(algorithm: YAMLMapNode,
-                      algoTmpl: DSLAlgorithm,
-                      resources: List[DSLResource]): DSLAlgorithm = {
-    val name = algorithm / Vocabulary.name match {
-      case x: YAMLStringNode => x.string
-      case YAMLEmptyNode => throw new DSLParseException("Algorithm does not have a name")
-    }
-
-    val overr = algorithm / Vocabulary.overrides match {
-      case x: YAMLStringNode => Some(algoTmpl)
-      case YAMLEmptyNode => None
-    }
-
-    val algos = resources.map {
-      r =>
-        val algo = algorithm / r.name match {
-          case x: YAMLStringNode => x.string
-          case y: YAMLIntNode => y.int.toString
-          case YAMLEmptyNode => algoTmpl.equals(DSLAlgorithm.emptyAlgorithm) match {
-            case false => algoTmpl.algorithms.getOrElse(r,
-              throw new DSLParseException(("Superalgo does not specify an algorithm for resource:%s").format(r.name)))
-            case true => throw new DSLParseException(("Cannot find calculation algorithm for resource %s in either " +
-              "algorithm %s or a superalgorithm").format(r.name, name))
-          }
-        }
-        Map(r -> algo)
-    }.foldLeft(Map[DSLResource, String]())((x,y) => x ++ y)
-
-    val timeframe = algorithm / Vocabulary.effective match {
-      case x: YAMLMapNode => parseTimeFrame(x)
-      case YAMLEmptyNode => algoTmpl.equals(DSLAlgorithm.emptyAlgorithm) match {
-        case false => algoTmpl.effective
-        case true => throw new DSLParseException(("Cannot find effectivity period for algorithm %s ").format(name))
-      }
-    }
-
-    DSLAlgorithm(name, overr, algos, timeframe)
-  }
-
-  /** Parse top level pricelist declarations */
-  private def parsePriceLists(pricelists: YAMLListNode,
-                    resources: List[DSLResource],
-                    results: List[DSLPriceList]): List[DSLPriceList] = {
-    pricelists.head match {
-      case YAMLEmptyNode => return List()
-      case _ =>
-    }
-
-    val superName = pricelists.head / Vocabulary.overrides
-    val tmpl = superName match {
-      case y: YAMLStringNode =>
-        results.find(p => p.name.equals(y.string)) match {
-          case Some(x) => x
-          case None => throw new DSLParseException("Cannot find super pricelist %s".format(superName))
-        }
-      case YAMLEmptyNode => DSLPriceList.emptyPriceList
-      case _ => throw new DSLParseException("Super pricelist name %s not a string".format())
-    }
-
-    val pl = constructPriceList(pricelists.head.asInstanceOf[YAMLMapNode],
-      tmpl, resources)
-
-    val tmpresults = pl :: results
-    pl :: parsePriceLists(pricelists.tail, resources, tmpresults)
-  }
-
-  /* Construct a pricelist from a YAML node and template, which may be
-  * an empty pricelist or an inhereted pricelist definition.
-  */
-  def constructPriceList(pl: YAMLMapNode, tmpl: DSLPriceList,
-                         resources: List[DSLResource]): DSLPriceList = {
-    val name = pl / Vocabulary.name match {
-      case x: YAMLStringNode => x.string
-      case YAMLEmptyNode => throw new DSLParseException(
-        "Pricelist does not have a name")
-    }
-
-    val overr = pl / Vocabulary.overrides match {
-      case x: YAMLStringNode => Some(tmpl)
-      case YAMLEmptyNode => None
-    }
-
-    val prices = resources.map {
-      r =>
-        val price = pl / r.name match {
-          case y: YAMLIntNode => y.int.toDouble
-          case z: YAMLDoubleNode => z.double.toDouble
-          case a: YAMLStringNode => a.string.toDouble
-          case YAMLEmptyNode => tmpl.equals(DSLAlgorithm.emptyAlgorithm) match {
-            case false => tmpl.prices.getOrElse(r,
-              throw new DSLParseException(("Superpricelist does not specify a price for resource:%s").format(r.name)))
-            case true => throw new DSLParseException(("Cannot find price for resource %s in either pricelist %s or " +
-              "its super pricelist").format(r.name, name))
-          }
-        }
-        Map(r -> price)
-    }.foldLeft(Map[DSLResource, Double]())((x, y) => x ++ y)
-
-    val timeframe = pl / Vocabulary.effective match {
-      case x: YAMLMapNode => parseTimeFrame(x)
-      case YAMLEmptyNode => tmpl.equals(DSLAlgorithm.emptyAlgorithm) match {
-        case false => tmpl.effective
-        case true => throw new DSLParseException(("Cannot find effectivity period for pricelist %s").format(name))
-      }
-    }
-    DSLPriceList(name, overr, prices, timeframe)
-  }
-
-  private def parseCreditPlans(creditsplans: YAMLListNode,
-                               results: List[DSLCreditPlan]) : List[DSLCreditPlan] = {
-    creditsplans.head match {
-      case YAMLEmptyNode => return List()
-      case _ =>
-    }
-
-    val superName = creditsplans.head / Vocabulary.overrides
-    val tmpl = superName match {
-      case y: YAMLStringNode =>
-        results.find(p => p.name.equals(y.string)) match {
-          case Some(x) => x
-          case None => throw new DSLParseException("Cannot find super credit plan %s".format(superName))
-        }
-      case YAMLEmptyNode => DSLCreditPlan.emptyCreditPlan
-      case _ => throw new DSLParseException("Super credit plan name %s not a string".format())
-    }
-
-    val plan = constructCreditPlan(creditsplans.head.asInstanceOf[YAMLMapNode], tmpl)
-
-    val tmpresults = plan :: results
-    plan :: parseCreditPlans(creditsplans.tail, tmpresults)
-  }
-
-  def constructCreditPlan(plan: YAMLMapNode, tmpl: DSLCreditPlan): DSLCreditPlan = {
-
-    val name = plan / Vocabulary.name match {
-      case x: YAMLStringNode => x.string
-      case YAMLEmptyNode => throw new DSLParseException(
-        "Credit plan does not have a name")
-    }
-
-    val overr = plan / Vocabulary.overrides match {
-      case x: YAMLStringNode => Some(tmpl)
-      case YAMLEmptyNode => None
-    }
-
-    val at = plan / Vocabulary.at match {
-      case x: YAMLStringNode => parseCronString(x.string)
-      case YAMLEmptyNode => throw new DSLParseException(
-        "Credit plan does not define repetition specifier")
-    }
-
-    val atCron = (plan / Vocabulary.at).asInstanceOf[YAMLStringNode]
-
-    val credits = plan / Vocabulary.credits match {
-      case x: YAMLIntNode => x.int.toDouble
-      case y: YAMLDoubleNode => y.double.toDouble
-      case YAMLEmptyNode => throw new DSLParseException(
-        "Credit plan does not have a name")
-    }
-
-    val timeframe = plan / Vocabulary.effective match {
-      case x: YAMLMapNode => parseTimeFrame(x)
-      case YAMLEmptyNode => tmpl.equals(DSLCreditPlan.emptyCreditPlan) match {
-        case false => tmpl.effective
-        case true => throw new DSLParseException(
-          ("Cannot find effectivity period for creditplan %s").format(name))
-      }
-    }
-
-    DSLCreditPlan(name, overr, credits, at, atCron.string, timeframe)
-  }
-
-  /** Parse top level agreements */
-  private def parseAgreements(agreements: YAMLListNode,
-                      policies: List[DSLAlgorithm],
-                      pricelists: List[DSLPriceList],
-                      resources: List[DSLResource],
-                      creditplans: List[DSLCreditPlan],
-                      results: List[DSLAgreement]): List[DSLAgreement] = {
-     agreements.head match {
-       case YAMLEmptyNode => return List()
-       case _ =>
-     }
-
-     val superName = agreements.head / Vocabulary.overrides
-     val tmpl = superName match {
-       case y: YAMLStringNode =>
-         results.find(p => p.name.equals(y.string)) match {
-           case Some(x) => x
-           case None => throw new DSLParseException("Cannot find super agreement %s".format(superName))
-         }
-       case YAMLEmptyNode => DSLAgreement.emptyAgreement
-       case _ => throw new DSLParseException("Super agreement name %s not a string".format(superName))
-     }
-
-     val agr = constructAgreement(agreements.head.asInstanceOf[YAMLMapNode],
-       tmpl, policies, pricelists, resources, creditplans)
-
-     val tmpresults = agr :: results
-     agr :: parseAgreements(agreements.tail, policies, pricelists,
-       resources, creditplans, tmpresults)
-   }
-
-  def constructAgreement(agr: YAMLMapNode,
-                         tmpl: DSLAgreement,
-                         policies: List[DSLAlgorithm],
-                         pricelists: List[DSLPriceList],
-                         resources: List[DSLResource],
-                         creditplans: List[DSLCreditPlan]) : DSLAgreement = {
-     val name = agr / Vocabulary.name match {
-      case x: YAMLStringNode => x.string
-      case YAMLEmptyNode => throw new DSLParseException("Agreement does not have a name")
-    }
-
-    val algorithm = agr / Vocabulary.algorithm match {
-      case x: YAMLStringNode => policies.find(p => p.name.equals(x.string)) match {
-        case Some(y) => y
-        case None => throw new DSLParseException(("Cannot find algorithm named %s").format(x))
-      }
-      case y: YAMLMapNode =>
-        if (y / Vocabulary.name == YAMLEmptyNode)
-          y.map += (Vocabulary.name -> YAMLStringNode("/","%s-algorithm".format(name)))
-        constructAlgorithm(y, tmpl.algorithm, resources)
-      case YAMLEmptyNode => tmpl.equals(DSLAgreement.emptyAgreement) match {
-        case true => throw new DSLParseException(("No algorithm for agreement %s").format(name))
-        case false => tmpl.algorithm
-      }
-    }
-
-    val pricelist = agr / Vocabulary.pricelist match {
-      case x: YAMLStringNode => pricelists.find(p => p.name.equals(x.string)) match {
-        case Some(y) => y
-        case None => throw new DSLParseException(("Cannot find pricelist named %s").format(x))
-      }
-      case y: YAMLMapNode =>
-        if (y / Vocabulary.name == YAMLEmptyNode)
-          y.map += ("name" -> YAMLStringNode("/","%s-pricelist".format(name)))
-        constructPriceList(y, tmpl.pricelist, resources)
-      case YAMLEmptyNode => tmpl.equals(DSLAgreement.emptyAgreement) match {
-        case true => throw new DSLParseException(("No algorithm for agreement %s").format(name))
-        case false => tmpl.pricelist
-      }
-    }
-
-    val creditplan = agr / Vocabulary.creditplan match {
-      case x: YAMLStringNode => creditplans.find(p => p.name.equals(x.string)) match {
-        case Some(y) => y
-        case None => throw new DSLParseException(("Cannot find crediplan named %s").format(x))
-      }
-      case y: YAMLMapNode =>
-        if (y / Vocabulary.name == YAMLEmptyNode)
-          y.map += ("name" -> YAMLStringNode("/","%s-creditplan".format(name)))
-        constructCreditPlan(y, tmpl.creditplan)
-      case YAMLEmptyNode => tmpl.equals(DSLAgreement.emptyAgreement) match {
-        case true => throw new DSLParseException(("No creditplan for agreement %s").format(name))
-        case false => tmpl.creditplan
-      }
-    }
-
-    val overrides = tmpl.equals(DSLAgreement.emptyAgreement) match {
-      case false => Some(tmpl)
-      case true => None
-    }
-
-    DSLAgreement(name, overrides, algorithm, pricelist, creditplan)
-  }
-
-  /** Parse a timeframe declaration */
-  def parseTimeFrame(timeframe: YAMLMapNode): DSLTimeFrame = {
-    val from = timeframe / Vocabulary.from match {
-      case x: YAMLIntNode => new Date(x.int.longValue * 1000L)
-      case y: YAMLLongNode => new Date(y.long)
-      case _ => throw new DSLParseException("No %s field for timeframe %s".format(Vocabulary.from, timeframe))
-    }
-
-    val to = timeframe / Vocabulary.to match {
-      case x: YAMLIntNode => Some(new Date(x.int.longValue * 1000L))
-      case y: YAMLLongNode => Some(new Date(y.long))
-      case YAMLEmptyNode => None
-    }
-
-    val repeat =
-     timeframe / Vocabulary.repeat match {
-       case x: YAMLListNode => parseTimeFrameRepeat(x)
-      case YAMLEmptyNode => Nil
-    }
-
-    /*val cronRepeat = timeframe / "cron" match {
-      case x: YAMLListNode =>  parseCronSpecs(x)
-      case _ => Nil
-    }*/
-
-    DSLTimeFrame(from, to,repeat)
-  }
-
-  /*def parseCronSpecs(l: YAMLListNode) : List[DSLCronSpec] =
-      l.listValue map  {
-        case x:YAMLStringNode => new DSLCronSpec(x.string.trim)
-        case YAMLEmptyNode => throw new DSLParseException("Bad cron expression")
-      }*/
-
-  /** Parse a resource frame repeat block */
-  def parseTimeFrameRepeat(tmr: YAMLListNode): List[DSLTimeFrameRepeat] = {
-
-    if (tmr.isEmpty)
-      return List()
-
-
-    /** Parse a resource frame entry (start, end tags) */
-    def findInMap(repeat: YAMLMapNode,
-                  tag: String) : (String, List[DSLTimeSpec]) = {
-      repeat / tag match {
-        case x: YAMLStringNode => (x.string, parseCronString(x.string))
-        case YAMLEmptyNode => throw new DSLParseException("No %s field for repeat entry %s".format(tag, repeat))
-      }
-    }
-
-    val start = findInMap(tmr.head.asInstanceOf[YAMLMapNode], Vocabulary.start)
-    val end = findInMap(tmr.head.asInstanceOf[YAMLMapNode], Vocabulary.end)
-    assert(start._2.size == end._2.size)
-    DSLTimeFrameRepeat(start._2, end._2, start._1,end._1) :: parseTimeFrameRepeat(tmr.tail)
-  }
-
-  /** 
-   * Wraps the [[http://kenai.com/projects/crontab-parser/pages/Home crontabparser]]
-   * library to parse crontab-like strings. The input format differs from the
-   * [[http://en.wikipedia.org/wiki/Cron default cron format]] in the following ways:
-   *
-   *  - Only 5 field cron specs are allowed
-   *  - Multiple values per field (e.g. Mon,Wed,Fri) are not allowed. Ranges
-   *    (e.g. Mon-Fri) are however allowed.
-   */
-  def parseCronString(input: String): List[DSLTimeSpec] = {
-
-    if (input.split(" ").length != 5)
-      throw new DSLParseException("Only five-field cron strings allowed: " + input)
-
-    val cron = try {
-      asScalaBuffer(CronTabParserBridge.parse(input))
-    } catch {
-      case e => throw new DSLParseException("Error parsing cron string: " + e.getMessage)
-    }
-    def splitMultiVals(ii : Int): List[Int] = {
-      val input = cron.get(ii).toString
-      if (input.equals("*"))
-        (-1).until(0).toList
-       //TODO:  DO NOT ACCEPT "-" and ","
-      else if (input.contains('-')) {
-        val ints = input.split('-')
-        ints(0).toInt.until(ints(1).toInt + 1).toList
-      } else if (input.contains(','))
-        input.split(',').map(_.toInt).toList
-       else
-        input.toInt.until(input.toInt + 1).toList
-    }
-    for { a <- splitMultiVals(0)
-          b <- splitMultiVals(1)
-          c <- splitMultiVals(2)
-          d <- splitMultiVals(3)
-          e <- splitMultiVals(4)}
-    yield
-       DSLTimeSpec(a,b,c,d,e)
-  }
-}
-
-/** Exception thrown when a parsing error occurs*/
-class DSLParseException(msg: String) extends Exception(msg)
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLAgreement.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLAgreement.scala
deleted file mode 100644 (file)
index e945377..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-/**
- * An agreement associates algorithms with priceslists within and
- * effectivity period.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-
-case class DSLAgreement (
-  name: String,
-  overrides: Option[DSLAgreement],
-  algorithm : DSLAlgorithm,
-  pricelist : DSLPriceList,
-  creditplan: DSLCreditPlan
-) extends DSLItem {
-
-  override def toMap(): Map[String, Any] = {
-    val parent = overrides match {
-      case Some(x) => Map(Vocabulary.overrides -> x.name)
-      case _ => Map()
-    }
-
-    parent                                        ++
-    Map(Vocabulary.name -> name)                  ++
-    Map(Vocabulary.algorithm  -> algorithm.toMap)  ++
-    Map(Vocabulary.pricelist  -> pricelist.toMap)  ++
-    Map(Vocabulary.creditplan -> creditplan.toMap)
-  }
-}
-
-object DSLAgreement {
-  val emptyAgreement = DSLAgreement("", None, DSLAlgorithm.emptyAlgorithm,
-    DSLPriceList.emptyPriceList, DSLCreditPlan.emptyCreditPlan)
-
-  final val DefaultAgreementName = "default"
-}
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLAlgorithm.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLAlgorithm.scala
deleted file mode 100644 (file)
index 67c6a45..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import com.ckkloverdos.maybe.Maybe
-
-import gr.grnet.aquarium.util.findFromMapAsMaybe
-
-/**
- * An algorithm represents the way of calculating costs given a price
- * and a resource usage volume.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-case class DSLAlgorithm (
-  override val name: String,
-  override val overrides: Option[DSLAlgorithm],
-  algorithms: Map[DSLResource, String],
-  override  val effective: DSLTimeFrame
-) extends DSLTimeBoundedItem[DSLAlgorithm](name, overrides, effective) {
-
-  override def toMap() =
-    super.toMap ++ algorithms.map(x => (x._1.name, x._2))
-  
-  def findDefinitionForResource(resourceDef: DSLResource): Maybe[String] = {
-    findFromMapAsMaybe(algorithms, resourceDef)
-  }
-}
-
-object DSLAlgorithm {
-  val emptyAlgorithm = DSLAlgorithm("", None, Map(), DSLTimeFrame.emptyTimeFrame)
-}
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLCreditPlan.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLCreditPlan.scala
deleted file mode 100644 (file)
index 00d9c9e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-/**
- * A credit plan specifies a periodic transfer of credits to an
- * account.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-case class DSLCreditPlan (
-  override val name: String,
-  override  val overrides: Option[DSLCreditPlan],
-  credits: Double,
-  at: List[DSLTimeSpec],
-  atCron: String,
-  override val effective: DSLTimeFrame
-) extends DSLTimeBoundedItem[DSLCreditPlan](name, overrides, effective) {
-
-  override def toMap(): Map[String, Any] =
-    super.toMap ++ Map(Vocabulary.credits -> credits) ++ Map(Vocabulary.at -> atCron)
-}
-
-object DSLCreditPlan {
-  val emptyCreditPlan = DSLCreditPlan("", None, 0, List(), "", DSLTimeFrame.emptyTimeFrame)
-}
index 8cf6cfa..18864b7 100644 (file)
@@ -42,7 +42,7 @@ import java.util.Date
  * @author Prodromos Gerakios <pgerakios@grnet.gr>
  */
 
-case class DSLCronSpec(cronSpec: String) extends DSLItem {
+case class DSLCronSpec(cronSpec: String) {
 
     private val cronExpr = {
       val e = "00 " + cronSpec.trim //IMPORTANT: WE DO NOT CARE ABOUT SECONDS!!!
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLPolicy.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLPolicy.scala
deleted file mode 100644 (file)
index dd27c9e..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import gr.grnet.aquarium.util.CryptoUtils
-import gr.grnet.aquarium.util.date.TimeHelpers
-import gr.grnet.aquarium.event.model.PolicyEntry
-
-/**
- * Root object for the Aquarium policy configuration tree.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-case class DSLPolicy (
-  algorithms: List[DSLAlgorithm],
-  pricelists: List[DSLPriceList],
-  resources: List[DSLResource],
-  creditplans: List[DSLCreditPlan],
-  agreements: List[DSLAgreement]
-) extends DSLItem {
-
-  /**Find a resource by name */
-  def findResource(name: String): Option[DSLResource] = {
-    resources.find(a => a.name.equals(name))
-  }
-
-  /**Find a pricelist by name */
-  def findPriceList(name: String): Option[DSLPriceList] = {
-    pricelists.find(a => a.name.equals(name))
-  }
-
-  /**Find an algorithm by name */
-  def findAlgorithm(name: String): Option[DSLAlgorithm] = {
-    algorithms.find(a => a.name.equals(name))
-  }
-
-  /**Find a crediplan by name */
-  def findCreditPlan(name: String): Option[DSLCreditPlan] = {
-    creditplans.find(a => a.name.equals(name))
-  }
-
-  /**Find an agreement by name */
-  def findAgreement(name: String): Option[DSLAgreement] = {
-    agreements.find(a => a.name.equals(name))
-  }
-
-  override def toMap() = {
-    val policy = Map(Vocabulary.resources   -> resources.map{r => r.toMap})   ++
-    Map(Vocabulary.algorithms  -> algorithms.map{a => a.toMap})  ++
-    Map(Vocabulary.pricelists  -> pricelists.map{p => p.toMap})  ++
-    Map(Vocabulary.creditplans -> creditplans.map{c => c.toMap}) ++
-    Map(Vocabulary.agreements  -> agreements.map{a => a.toMap})
-    Map(Vocabulary.aquariumpolicy -> policy)
-  }
-
-  def resourcesMap: DSLResourcesMap =
-    new DSLResourcesMap(resources)
-
-  def toPolicyEntry: PolicyEntry = {
-    val yaml = toYAML
-    val now = TimeHelpers.nowMillis()
-    // FIXME: Define proper validity period instead of [0L, Long.MaxValue)
-    PolicyEntry(CryptoUtils.sha1(yaml), now, now, yaml, 0L, Long.MaxValue)
-  }
-
-  def toPolicyEntry(occurredMillis: Long, validFromMillis: Long, validToMillis: Long = Long.MaxValue) = {
-    val yaml = toYAML
-    val id = CryptoUtils.sha1(yaml)
-    PolicyEntry(id, occurredMillis,  occurredMillis, yaml, validFromMillis, validToMillis)
-  }
-}
-
-object DSLPolicy {
-
-  val emptyPolicy = DSLPolicy(List(), List(), List(), List(), List())
-
-  object JsonNames {
-    val valid = "valid"
-    val _id = "_id"
-  }
-}
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLPriceList.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLPriceList.scala
deleted file mode 100644 (file)
index 9a59a7e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-/**
- * A pricelist assigns a price tag to a unit of resource usage, per resource.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-case class DSLPriceList (
-  override val name: String,
-  override val overrides: Option[DSLPriceList],
-  prices: Map[DSLResource,  Double],
-  override val effective: DSLTimeFrame
-) extends DSLTimeBoundedItem[DSLPriceList](name, overrides, effective) {
-  
-  override def toMap(): Map[String, Any] =
-    super.toMap ++ prices.map{x => (x._1.name -> x._2)}
-}
-
-object DSLPriceList {
-  /**An empty pricelist */
-  val emptyPriceList = DSLPriceList("", None, Map(), DSLTimeFrame.emptyTimeFrame)
-}
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLResource.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLResource.scala
deleted file mode 100644 (file)
index 119507f..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-/**
- * Represents a chargeable resource.
- *
- * @param name
- * @param unit
- * @param costPolicy
- */
-case class DSLResource (
-  name: String,
-  unit: String,
-  costPolicy: DSLCostPolicy,
-  isComplex: Boolean = false,
-  descriminatorField: String = "instanceId"
-) extends DSLItem {
-
-  override def toMap(): Map[String, Any] =
-    Map(Vocabulary.name -> name) ++
-    Map(Vocabulary.unit -> unit) ++
-    Map(Vocabulary.costpolicy -> costPolicy.name) ++
-    Map(Vocabulary.complex -> isComplex) ++
-    Map(Vocabulary.descriminatorfield -> descriminatorField)
-}
-
-object DSLResource {
-  final val SimpleResourceInstanceId = "1"
-  final val SomeSimpleResourceInstanceId = Some(SimpleResourceInstanceId)
-}
-
-object DSLSimpleResource {
-  def apply(name: String, unit: String, costPolicy: DSLCostPolicy) = {
-    DSLResource(name, unit, costPolicy)
-  }
-}
-
-object DSLComplexResource {
-  def apply(name: String, unit: String, costPolicy: DSLCostPolicy) = {//, descriminatorField: String) = {
-    DSLResource(name, unit, costPolicy, true)
-  }
-}
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLSemanticChecks.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLSemanticChecks.scala
deleted file mode 100644 (file)
index 2fc60c6..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import java.util.Date
-import scala.collection._
-//TODO: REMOVE THIS CLASS
-/**
- * A semantic checker for the Aquarium accounting DSL. 
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-/*trait DSLSemanticChecks {
-
-  /**
-   * Functions to apply by default when checking consistency for
-   * [[gr.grnet.aquarium.logic.dsl.DSLAlgorithm]] resources.
-   */
-  val policyChecks = List[DSLAlgorithm => List[DSLConsistencyMsg]](
-  )
-
-  /**
-   * Functions to apply by default when checking consistency for
-   * [[gr.grnet.aquarium.logic.dsl.DSLPriceList]] resources.
-   */
-  val priceListChecks = List[DSLPriceList => List[DSLConsistencyMsg]](
-  )
-
-  /**
-   * Functions to apply by default when checking consistency for
-   * [[gr.grnet.aquarium.logic.dsl.DSLAgreement]] resources.
-   */
-  val agreementChecks = List[DSLAgreement => List[DSLConsistencyMsg]](
-  )
-
-  /**
-   * Functions to apply by default when checking consistency for
-   * [[gr.grnet.aquarium.logic.dsl.DSLTimeFrame]] resources.
-   */
-  val timeFrameChecks = List[DSLTimeFrame => List[DSLConsistencyMsg]](
-    checkTimeFrameFromTo,
-    checkTimeNotInitialized,
-    checkRepeatHoles
-  )
-
-  /**
-   * Apply a list of consistency checking functions to a DSL entity and
-   * report results.
-   */
-  def check[A](resource: A, checks: List[A => List[DSLConsistencyMsg]]) :
-    List[DSLConsistencyMsg] = {
-    checks.map(f => f(resource)).flatten.toList
-  }
-
-  /**
-   * Top level consistency check functions. Applies all tests on all resources.
-   */
-  def check(creditPolicy: DSLPolicy) : List[DSLConsistencyMsg] = {
-    List[DSLConsistencyMsg]() ++
-      creditPolicy.pricelists.flatMap(p => check(p)) ++
-      creditPolicy.algorithms.flatMap(p => check(p)) ++
-      creditPolicy.agreements.flatMap(a => check(a))
-  }
-
-  /** Apply [[gr.grnet.aquarium.logic.dsl.DSLPriceList]] related checks on a pricelist */
-  def check(pl: DSLPriceList): List[DSLConsistencyMsg] = check(pl, priceListChecks)
-
-  /** Apply [[gr.grnet.aquarium.logic.dsl.DSLAlgorithm]] related checks on a algorithm */
-  def check(pl: DSLAlgorithm): List[DSLConsistencyMsg] = check(pl, policyChecks)
-
-  /** Apply [[gr.grnet.aquarium.logic.dsl.DSLAgreement]] related checks on a algorithm */
-  def check(pl: DSLAgreement): List[DSLConsistencyMsg] = check(pl, agreementChecks)
-
-  /** Apply [[gr.grnet.aquarium.logic.dsl.DSLTimeframe]] related checks on a timeframe */
-  def check(time: DSLTimeFrame): List[DSLConsistencyMsg] = check(time, timeFrameChecks)
-
-  /* -- Checker functions -- */
-  private def checkTimeFrameFromTo(time: DSLTimeFrame) : List[DSLConsistencyMsg] = {
-    if (time.from.after(time.to.getOrElse(new Date(0))))
-      List(DSLConsistencyError("Validity period %s ends before starting".format(time)))
-    else
-      List()
-  }
-
-  private def checkTimeNotInitialized(time: DSLTimeFrame) : List[DSLConsistencyMsg] = {
-    if (time.repeat.isEmpty)
-      return List()
-
-    val result = new mutable.ListBuffer[DSLConsistencyMsg]
-
-    time.repeat.foreach {
-      r =>
-        r.start.foreach {
-          r => if (r.hour == -1 || r.min == -1)
-            result += DSLConsistencyError(
-              "Hours and mins must always be initialized: %s".format(time))
-        }
-
-        r.end.foreach {
-          e =>  if (e.hour == -1 || e.min == -1)
-            result += DSLConsistencyError(
-              "Hours and mins must always be initialized: %s".format(time))
-        }
-    }
-    result.toList
-  }
-
-  private def checkRepeatHoles(time: DSLTimeFrame) : List[DSLConsistencyMsg] = {
-    val repeat = time.repeat
-
-    List()
-  }
-}
-
-sealed trait DSLConsistencyMsg
-case class DSLConsistencyWarn(warn: String) extends DSLConsistencyMsg
-case class DSLConsistencyError(err: String) extends DSLConsistencyMsg*/
index a32b41e..7b1c043 100644 (file)
@@ -45,21 +45,7 @@ import java.util.Date
  */
 abstract class DSLTimeBoundedItem[T <: DSLTimeBoundedItem[T]](val name: String,
                                                               val overrides: Option[T],
-                                                              val effective: DSLTimeFrame)
-extends DSLItem {
+                                                              val effective: DSLTimeFrame) {
 
   def toTimeslot : Timeslot = Timeslot(effective.from,effective.to.getOrElse(new Date(Long.MaxValue)))
-
-  override def toMap(): Map[String, Any] = {
-    val data = new scala.collection.mutable.HashMap[String, Any]()
-    data +=  ("name" -> name)
-    overrides match {
-      case Some(x) => data +=  ("overrides" -> x.name)
-      case _ =>
-    }
-
-    data += ("effective" -> effective.toMap())
-
-    data.toMap
-  }
 }
index 5ca271c..7d2454b 100644 (file)
@@ -37,11 +37,9 @@ package gr.grnet.aquarium.logic.accounting.dsl
 
 import gr.grnet.aquarium.util.shortNameOfClass
 
-import java.util.{GregorianCalendar, Date, Calendar}
+import java.util.Date
 import gr.grnet.aquarium.util.date.MutableDateCalc
 import collection.mutable
-import java.util
-import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
 
 /**
  * Represents an effectivity timeframe.
@@ -53,7 +51,7 @@ case class DSLTimeFrame (
   to: Option[Date],
   repeat: List[DSLTimeFrameRepeat] /*,
   cronRepeat: List[DSLCronSpec]*/
-) extends DSLItem {
+) {
 
   to match {
     case Some(x) =>
@@ -193,22 +191,6 @@ case class DSLTimeFrame (
           }
      }
 
-  override def toMap(): Map[String, Any] = {
-    val toTS = to match {
-      case Some(x) => Map(Vocabulary.to -> x.getTime)
-      case _ => Map()
-    }
-
-    val repeatMap = if (repeat.size > 0) {
-      Map(Vocabulary.repeat -> repeat.map{r => r.toMap})
-    } else {
-      Map()
-    }
-
-    toTS ++
-      Map(Vocabulary.from -> from.getTime) ++
-      repeatMap
-  }
 
   override def toString =
     //"%s(%s, %s,\n %s\n || cron: %s)".format(
index 3d592d4..c0f84ce 100644 (file)
@@ -44,50 +44,45 @@ import java.util.Date
  * @author Georgios Gousios <gousiosg@gmail.com>
  */
 case class DSLTimeFrameRepeat (
-  start: List[DSLTimeSpec],
-  end: List[DSLTimeSpec],
+//  start: List[DSLTimeSpec],
+//  end: List[DSLTimeSpec],
   startCron: String,
   endCron: String
-) extends DSLItem {
+) {
 
-  private def makeCronExpression(s: String) : CronExpression  = {
-    val e = "0 " + s.trim
-    val l = e.split(" ")
-    (l(3),l(5))  match {
-      case ("?",_) | (_,"?") => ()
-      case (_,"*") => l.update(5,"?")
-      case ("*",_) => l.update(3,"?")
-    }
-    val e1 = l.foldLeft("") { (s,elt) => s + " " + elt}
-    new CronExpression(e1)
-  }
+//  private def makeCronExpression(s: String) : CronExpression  = {
+//    val e = "0 " + s.trim
+//    val l = e.split(" ")
+//    (l(3),l(5))  match {
+//      case ("?",_) | (_,"?") => ()
+//      case (_,"*") => l.update(5,"?")
+//      case ("*",_) => l.update(3,"?")
+//    }
+//    val e1 = l.foldLeft("") { (s,elt) => s + " " + elt}
+//    new CronExpression(e1)
+//  }
   val getStart = DSLCronSpec(startCron)
   val getEnd =  DSLCronSpec(endCron)
 
-  assert(start.size == end.size,
-    ("start (%s) and end (%s) cron-like specs do not expand to equal" +
-      " number of repetition definitions").format(startCron, endCron))
+//  assert(start.size == end.size,
+//    ("start (%s) and end (%s) cron-like specs do not expand to equal" +
+//      " number of repetition definitions").format(startCron, endCron))
+//
+//  //Ensures that fields that have repeating entries, do so in both patterns
+//  start.zip(end).foreach {
+//    x =>
+//      assert((x._1.dom == -1 && x._2.dom == -1) ||
+//        (x._1.dom != -1 && x._2.dom != -1))
+//
+//      assert((x._1.mon == -1 && x._2.mon == -1) ||
+//        (x._1.mon != -1 && x._2.mon != -1))
+//
+//      assert((x._1.dow == -1 && x._2.dow == -1) ||
+//        (x._1.dow != -1 && x._2.dow != -1))
+//  }
 
-  //Ensures that fields that have repeating entries, do so in both patterns
-  start.zip(end).foreach {
-    x =>
-      assert((x._1.dom == -1 && x._2.dom == -1) ||
-        (x._1.dom != -1 && x._2.dom != -1))
-
-      assert((x._1.mon == -1 && x._2.mon == -1) ||
-        (x._1.mon != -1 && x._2.mon != -1))
-
-      assert((x._1.dow == -1 && x._2.dow == -1) ||
-        (x._1.dow != -1 && x._2.dow != -1))
-  }
-
-  override def toMap(): Map[String, Any] = {
-    Map[String,  Any]() ++
-    Map(Vocabulary.start -> startCron) ++
-    Map(Vocabulary.end -> endCron)
-  }
 }
 
 object DSLTimeFrameRepeat {
-  val emptyTimeFramRepeat = DSLTimeFrameRepeat(List(), List(), "", "")
+  val emptyTimeFramRepeat = DSLTimeFrameRepeat(/*List(), List(), */"", "")
 }
\ No newline at end of file
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLTimeSpec.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSLTimeSpec.scala
deleted file mode 100644 (file)
index a1cf615..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import java.util.{GregorianCalendar, Date, Calendar}
-import collection.mutable
-
-/**
- * Represents an instance of an expanded cronstring declaration. Enforces,
- * at object creation time, the following conditions:
- *
- *  - 0 < `min` < 60
- *  - 0 < `hour` < 24
- *  - -1 < `dom` < 31 and `dom` not equal to 0
- *  - -1 < `mon` < 12 and `mon` not equal to 0
- *  - -1 < `dow` < 7
- * 
- * A value of -1 for the fields `dom`,`mon` and `dow` means that the defined
- * time moment can be repeated within a timeframe.
- * `min` and `hour` fields cannot be used to define repetitive time moments.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-  case class DSLTimeSpec(
-    min: Int,
-    hour: Int,
-    dom: Int,
-    mon: Int,
-    dow: Int
-  ) extends DSLItem {
-  //Preconditions to force correct values on object creation
-  assert(0 <= min && 60 > min)
-  assert(0 <= hour && 24 > hour)
-  assert(-1 <= dom && 31 > dom && dom != 0)
-  assert(-1 <= mon && 12 > mon && mon != 0)
-  assert(-1 <= dow && 7 > dow)
-
-  /* calendar-related methods*/
-  private val cal = new GregorianCalendar()
-  private def initDay(init:Long) {
-    cal.setTimeInMillis(init)
-    cal.set(Calendar.MINUTE,min)
-    cal.set(Calendar.HOUR_OF_DAY,hour)
-    cal.set(Calendar.SECOND,0)
-  }
-  private def nextValidDay(end:Long) (): Date = {
-    var ret : Date = null
-    while (cal.getTimeInMillis <= end && ret == null) {
-      val valid : Boolean = (mon < 0  || cal.get(Calendar.MONTH) == getCalendarMonth()) &&
-                            (dom < 0  || cal.get(Calendar.DAY_OF_MONTH) == dom) &&
-                            (dow < 0  || cal.get(Calendar.DAY_OF_WEEK) == getCalendarDow())
-      if(valid)
-         ret = cal.getTime
-      cal.add(Calendar.DAY_OF_YEAR, 1)
-    }
-    ret
-  }
-
-  def expandTimeSpec(from: Date,  to: Date) : List[Date] = {
-    val result = new mutable.ListBuffer[Date]()
-    val nextDay = this.nextValidDay (to.getTime) _
-    var d : Date = null
-    initDay(from.getTime)
-    while({d=nextDay();d}!=null) result += d
-    result.toList
-  }
-
-  /** Day of week conversions to stay compatible with [[java.util.Calendar]] */
-  private def getCalendarDow(): Int = dow match {
-    case 0 => Calendar.SUNDAY
-    case 1 => Calendar.MONDAY
-    case 2 => Calendar.TUESDAY
-    case 3 => Calendar.WEDNESDAY
-    case 4 => Calendar.THURSDAY
-    case 5 => Calendar.FRIDAY
-    case 6 => Calendar.SATURDAY
-    case 7 => Calendar.SUNDAY
-  }
-
-  /** Month conversions to stay compatible with [[java.util.Calendar]] */
-  private def getCalendarMonth(): Int = mon match {
-    case 1 => Calendar.JANUARY
-    case 2 => Calendar.FEBRUARY
-    case 3 => Calendar.MARCH
-    case 4 => Calendar.APRIL
-    case 5 => Calendar.MAY
-    case 6 => Calendar.JUNE
-    case 7 => Calendar.JULY
-    case 8 => Calendar.AUGUST
-    case 9 => Calendar.SEPTEMBER
-    case 10 => Calendar.OCTOBER
-    case 11 => Calendar.NOVEMBER
-    case 12 => Calendar.DECEMBER
-  }
-}
-
-object DSLTimeSpec {
-  val emtpyTimeSpec = DSLTimeSpec(0,0, -1, -1, -1)
-
-  def expandTimeSpec(d0:DSLTimeSpec,d1:DSLTimeSpec, from: Date,  to: Date) : List[(Date,Date)] = {
-    assert(d0!=null)
-    assert(d1!=null)
-    assert(from!=null)
-    assert(to!=null)
-    val result = new mutable.ListBuffer[(Date,Date)]()
-    val d0_nextDay = d0.nextValidDay (to.getTime) _ /* iterator for valid dates of d0*/
-    val d1_nextDay = d1.nextValidDay (to.getTime) _ /* iterator for valid dates of d1*/
-    var d0_d : Date = null
-    d0.initDay(from.getTime)
-    while({d0_d=d0_nextDay();d0_d}!=null){
-      val d1_d : Date = {d1.initDay(d0_d.getTime);d1_nextDay()}
-      if(d1_d!=null) result += ((d0_d,d1_d))
-    }
-    result.toList
-  }
-}
\ No newline at end of file
index c2ce109..2500a27 100644 (file)
 
 package gr.grnet.aquarium.logic.accounting.dsl
 
-import gr.grnet.aquarium.util.DateUtils
-import java.util.{Date, GregorianCalendar, Calendar}
+import java.util.{Date}
 import scala.collection.immutable
-import java.util
+import gr.grnet.aquarium.policy.{EffectiveUnitPrice, AdHocFullPriceTableRef, PolicyDefinedFullPriceTableRef, PolicyModel, ResourceType, EffectivePriceTable, UserAgreementModel}
+import gr.grnet.aquarium.AquariumInternalError
 
 /**
  * Utility functions to use when working with DSL types.
@@ -46,54 +46,50 @@ import java.util
  * @author Georgios Gousios <gousiosg@gmail.com>
  */
 
-trait DSLUtils extends DateUtils {
-
-  val maxdate = new Date(Int.MaxValue * 1000L)
-
-  /**
-   * Resolves the effective algorithm for each chunk of the
-   * provided timeslot and returns it as a Map
-   */
-  def resolveEffectiveAlgorithmsForTimeslot(timeslot: Timeslot,
-                                           agr: DSLAgreement):
-  immutable.SortedMap[Timeslot, DSLAlgorithm] =
-    resolveEffective[DSLAlgorithm](timeslot, agr.algorithm)
-
+trait DSLUtils {
   /**
    * Resolves the effective price list for each chunk of the
    * provided timeslot and returns it as a Map
    */
-  def resolveEffectivePricelistsForTimeslot(timeslot: Timeslot,
-                                            agr: DSLAgreement):
-  immutable.SortedMap[Timeslot, DSLPriceList] =
-    resolveEffective[DSLPriceList](timeslot,agr.pricelist)
-
-  /*private def printPolicy[T <: DSLTimeBoundedItem[T]](t : T) : Unit = {
-    Console.err.println("Policy " + t.name + " " + t.toTimeslot + " DETAIL : " + t.effective)
-    t.overrides match {
-      case None => Console.println
-      case Some(t) => printPolicy(t)
+  def resolveEffectiveUnitPricesForTimeslot(
+      timeslot: Timeslot,
+      policy: PolicyModel,
+      agreement: UserAgreementModel,
+      resourceType: ResourceType
+  ): immutable.SortedMap[Timeslot, Double] = {
+
+    val role = agreement.role
+    val fullPriceTable = agreement.fullPriceTableRef match {
+      case PolicyDefinedFullPriceTableRef ⇒
+        policy.roleMapping.get(role) match {
+          case Some(fullPriceTable) ⇒
+            fullPriceTable
+
+          case None ⇒
+            throw new AquariumInternalError("Unknown role %s".format(role))
+        }
+
+      case AdHocFullPriceTableRef(fullPriceTable) ⇒
+        fullPriceTable
     }
-  }
 
-  private def printMap[T <: DSLTimeBoundedItem[T]](m: immutable.SortedMap[Timeslot, T]) = {
-    Console.err.println("BEGIN MAP: ")
-    for { (t,p) <- m.toList } Console.err.println("Timeslot " + t + "\t\t" + p.name)
-    Console.err.println("END MAP")
-  } */
+    val effectivePriceTable = fullPriceTable.perResource.get(resourceType.name) match {
+      case None ⇒
+        throw new AquariumInternalError("Unknown resource type %s".format(role))
 
-  def resolveEffective[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
-  immutable.SortedMap[Timeslot, T] = {
-    //Console.err.println("\n\nInput timeslot: " + timeslot0 + "\n\n")
-    ///printPolicy(policy)
-    val ret =  resolveEffective3(timeslot0,policy) //HERE
-    //printMap(ret)
-    ret
+      case Some(effectivePriceTable) ⇒
+        effectivePriceTable
+    }
+
+    resolveEffective3(timeslot, effectivePriceTable)
   }
 
-  def resolveEffective3[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
-  immutable.SortedMap[Timeslot, T] = {
-    assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
+
+  def resolveEffective3(
+      timeslot0: Timeslot,
+      effectivePriceTable: EffectivePriceTable
+  ): immutable.SortedMap[Timeslot, Double/*unit price*/] = {
+//    assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
     val timeslot = timeslot0 //TODO: timeslot0.align(5000)
     val subtimeslots_of_this_policy = Timeslot.mergeOverlaps(policy.effective intervalsOf timeslot)
     val subtimeslots_NOT_IN_this_policy = Timeslot.mergeOverlaps(timeslot.nonOverlappingTimeslots
index c67dd00..8168faf 100644 (file)
@@ -45,8 +45,7 @@ import gr.grnet.aquarium.util.date.MutableDateCalc
  *
  * @author Georgios Gousios <gousiosg@gmail.com>
  */
-final case class Timeslot(from: Date, to: Date)
-  extends DSLItem with Ordered[Timeslot] {
+final case class Timeslot(from: Date, to: Date) extends Ordered[Timeslot] {
 
   /* Preconditions to ensure correct object creations */
   assert(from != null)
diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Vocabulary.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Vocabulary.scala
deleted file mode 100644 (file)
index fa1ec06..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.accounting.dsl
-
-/**
- * Vocabulary of terms for the DSL
- */
-object Vocabulary {
-  val aquariumpolicy = "aquariumpolicy"
-  val creditplans = "creditplans"
-  val creditplan = "creditplan"
-  val at = "at"
-  val credits = "credits"
-  val resources = "resources"
-  val algorithms = "algorithms"
-  val algorithm = "algorithm"
-  val pricelists = "pricelists"
-  val pricelist = "pricelist"
-  val agreements = "agreements"
-  val agreement = "agreement"
-  val name = "name"
-  val overrides = "overrides"
-  val effective = "effective"
-  val from = "from"
-  val to = "to"
-  val repeat = "repeat"
-  val start = "start"
-  val end = "end"
-  val unit = "unit"
-  val complex = "complex"
-  val costpolicy = "costpolicy"
-  val descriminatorfield = "descriminatorfield"
-  val instanceid = "instanceid"
-}
diff --git a/src/main/scala/gr/grnet/aquarium/policy/ChargingType.scala b/src/main/scala/gr/grnet/aquarium/policy/ChargingType.scala
deleted file mode 100644 (file)
index 7a53c32..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.policy
-
-/**
- * A charging type gives a name to an existing charging behavior. The idea is to be able to reuse
- * the same charging behavior for charge types that may be advertised differently. For example, buying a book
- * and issuing a direct credit discount have the exactly same charging behavior (just add/subtract a specific
- * amount of credits to/from the wallet) but they are different business-wise.<p/>
- *
- * Using the original terminology of Aquarium, `vmtime` is a charging type. The exact implementation code that
- * implements the semantics of `vmtime` is its charging behavior.
- *
- * @param name     The name (alias) of the charging behaviour. Examples are
- *                 `vmtime`, `diskspace`, `bandwidth`.
- *
- * @param behavior The implementation class for the charging behaviour.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>
- */
-case class ChargingType(name: String, behavior: ChargingBehavior)
index 147a59d..72fa2fd 100644 (file)
@@ -40,4 +40,4 @@ package gr.grnet.aquarium.policy
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-case class EffectiveUnitPrice(unitPrice: Double, when: String)
+case class EffectiveUnitPrice(unitPrice: Double, when: List[(String, String)])
index 904c344..e06d779 100644 (file)
@@ -42,7 +42,11 @@ package gr.grnet.aquarium.policy
  */
 
 case class FullPriceTable(perResource: Map[String/*Resource*/, EffectivePriceTable]) {
-  def effectiveProceTableForResource(resource: String): Option[EffectivePriceTable] = {
-    perResource.get(resource)
+  def effectivePriceTableForResourceType(resourceType: String): Option[EffectivePriceTable] = {
+    perResource.get(resourceType)
+  }
+
+  def effectivePriceTableForResourceType(resourceType: ResourceType): Option[EffectivePriceTable] = {
+    perResource.get(resourceType.name)
   }
 }
index 17ad6f9..7e6fa50 100644 (file)
@@ -35,7 +35,9 @@
 
 package gr.grnet.aquarium.policy
 
-import gr.grnet.aquarium.Timespan
+import gr.grnet.aquarium.{AquariumInternalError, Timespan}
+import gr.grnet.aquarium.util.json.JsonSupport
+import gr.grnet.aquarium.charging.ChargingBehavior
 
 /**
  * A policy is the fundamental business-related configuration of Aquarium.
@@ -47,12 +49,12 @@ import gr.grnet.aquarium.Timespan
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-trait PolicyModel {
+trait PolicyModel extends JsonSupport {
   def id: String
 
   def parentID: Option[String]
 
-  def idInStore: String
+  def idInStore: Option[Any]
 
 
   /**
@@ -60,16 +62,14 @@ trait PolicyModel {
    */
   def validityTimespan: Timespan
 
-  /**
-   * All known resource types for the policy's validity period.
-   */
-  def resourceTypes: Set[ResourceType]
+  final def validFrom: Long = validityTimespan.fromMillis
 
+  final def validTo: Long = validityTimespan.toMillis
 
   /**
-   * All known charging types for the policy's validity period.
+   * All known resource types for the policy's validity period.
    */
-  def chargingTypes: Set[ChargingType]
+  def resourceTypes: Set[ResourceType]
 
   /**
    * All known charging behaviors for the policy's validity period.<p/>
@@ -77,7 +77,7 @@ trait PolicyModel {
    * Note than since a charging behavior is semantically attached to an implementation, a change in the set
    * of known charging behaviors normally means a change in the implementation of Aquarium.
    */
-  def chargingBehaviors: List[ChargingBehavior]
+  def chargingBehaviorClasses: Set[String/*ImplementationClassName*/]
 
   /**
    * Each role is mapped to a full price table.
@@ -94,4 +94,13 @@ trait PolicyModel {
    */
   def roles: Set[String] = roleMapping.keySet
 
+  def resourceTypesMap: Map[String, ResourceType] = Map(resourceTypes.map(rt ⇒ (rt.name, rt)).toSeq: _*)
+}
+
+object PolicyModel {
+  trait NamesT {
+    final val a = 1
+  }
+
+  final object Names extends NamesT
 }
index def1e92..d01da5e 100644 (file)
 
 package gr.grnet.aquarium.policy
 
+import gr.grnet.aquarium.charging.ChargingBehavior
+
 /**
  * The definition of a resource type. A resource type is a broad classification to which resource instances belong.
  *
- * @param name
- * @param unit
- * @param chargingTypeName
+ * @param name The name of this resource type. Examples are `vmtime`, `diskspace`, `bandwidth`, `diskio`.
+ * @param unit The unit we use to count the resource usage.
+ * @param chargingBehavior The charging behavior used for this resource types.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case class ResourceType(name: String, unit: String, chargingTypeName: String)
+case class ResourceType(name: String, unit: String, chargingBehavior: ChargingBehavior)
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import gr.grnet.aquarium.util.yaml.YAMLHelpers
-
-import gr.grnet.aquarium.util.CollectionUtils
+package gr.grnet.aquarium.policy
 
+import gr.grnet.aquarium.Timespan
 
 /**
+ * Standard implementation of Aquarium policy model.
  *
- * @author Georgios Gousios <gousiosg@gmail.com>
+ * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-abstract class DSLItem  {
-  def toMap(): Map[String,  Any] =
-    (Map[String, Any]() /: this.getClass.getDeclaredFields) {
-      (a, f) =>
-        f.setAccessible(true)
-        a + (f.getName -> f.get(this))
-    }
+case class StdPolicy(
+    id: String,
+    parentID: Option[String],
+    validityTimespan: Timespan,
+    resourceTypes: Set[ResourceType],
+    chargingBehaviorClasses: Set[String],
+    roleMapping: Map[String/*Role*/, FullPriceTable]
+) extends PolicyModel {
 
-  def toYAML: String = YAMLHelpers.dumpYAML(toMap)
-}
\ No newline at end of file
+  def idInStore = Some(id)
+}
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.util.yaml
+package gr.grnet.aquarium.policy
+
+import gr.grnet.aquarium.Timespan
 
 /**
  *
- * @author Georgios Gousios <gousiosg@gmail.com>.
+ * @author Christos KK Loverdos <loverdos@gmail.com>
  */
-case class YAMLLongNode(path: String,  long: Long) extends YAMLNode {
-  def /(childName: String) = YAMLEmptyNode
 
-  override def longValue = long
-  override def isLong = true
+case class StdUserAgreement(
+    id: String,
+    parentID: Option[String],
+    validityTimespan: Timespan,
+    role: String,
+    fullPriceTableRef: FullPriceTableRef
+) extends UserAgreementModel {
 
-  def withPath(newPath: String) = this.copy(path = newPath)
+  def idInStore: Option[Any] = None
 }
index 92597b2..734773a 100644 (file)
@@ -45,7 +45,7 @@ import gr.grnet.aquarium.Timespan
 trait UserAgreementModel {
   def id: String
 
-  def idInStore: String
+  def idInStore: Option[Any]
 
   def parentID: Option[String]
 
@@ -54,4 +54,10 @@ trait UserAgreementModel {
   def role: String
 
   def fullPriceTableRef: FullPriceTableRef
+
+  def timeslot = validityTimespan.toTimeslot
+
+  def validFrom = validityTimespan.fromMillis
+
+  def validTo = validityTimespan.toMillis
 }
diff --git a/src/main/scala/gr/grnet/aquarium/service/RoleableActorProviderService.scala b/src/main/scala/gr/grnet/aquarium/service/RoleableActorProviderService.scala
deleted file mode 100644 (file)
index 5d1556a..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.service
-
-import akka.actor.ActorRef
-import com.ckkloverdos.props.Props
-import gr.grnet.aquarium.util.Lifecycle
-import gr.grnet.aquarium.actor.ActorRole
-import gr.grnet.aquarium.AquariumAware
-
-/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-trait RoleableActorProviderService extends Lifecycle {
-  /**
-   * Tries to find and provide the actor of specific `role`.
-   * Any extra info needed for the provision is given with the `hints` parameter.
-   *
-   * If no such actor is found, then this method throws an exception.
-   */
-  @throws(classOf[Exception])
-  def actorForRole(role: ActorRole, hints: Props = Props.empty): ActorRef
-}
\ No newline at end of file
index 1990d18..ad322a4 100644 (file)
@@ -35,7 +35,6 @@
 
 package gr.grnet.aquarium.simulation
 
-import gr.grnet.aquarium.logic.accounting.dsl.DSLResourcesMap
 import gr.grnet.aquarium.store.ResourceEventStore
 import java.util.Date
 
@@ -47,7 +46,5 @@ import java.util.Date
  */
 
 case class AquariumSim(resources: List[ResourceSim], resourceEventStore: ResourceEventStore) {
-  def resourcesMap = new DSLResourcesMap(resources.map(_.toDSLResource))
-  
   def newUser(userId: String, userCreationDate: Date) = UserSim(userId, userCreationDate, this)
 }
index 9410dbe..f9bf56d 100644 (file)
@@ -35,8 +35,9 @@
 
 package gr.grnet.aquarium.simulation
 
-import gr.grnet.aquarium.logic.accounting.dsl.{DSLResource, DSLCostPolicy}
 import gr.grnet.aquarium.util.shortClassNameOf
+import gr.grnet.aquarium.policy.ResourceType
+import gr.grnet.aquarium.charging.ChargingBehavior
 
 
 /**
@@ -45,28 +46,22 @@ import gr.grnet.aquarium.util.shortClassNameOf
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-class ResourceSim(val name: String,
-                  val unit: String,
-                  val costPolicy: DSLCostPolicy,
-                  val isComplex: Boolean = false,
-                  val descriminatorField: String = "instanceId") {
-  def toDSLResource = DSLResource(name, unit, costPolicy, isComplex, descriminatorField)
+class ResourceSim(val name: String, val unit: String, val chargingBehavior: ChargingBehavior ) {
+
+  def toResourceType = ResourceType(name, unit, chargingBehavior)
 
   def newInstance(instanceId: String, owner: UserSim, client: ClientSim) =
     new ResourceInstanceSim(this, instanceId, owner, client)
 
   override def toString = "%s(%s)".format(
     shortClassNameOf(this),
-    List(name, unit, costPolicy, isComplex, descriminatorField).mkString(","))
+    List(name, unit, chargingBehavior).mkString(","))
 }
 
 
 object ResourceSim {
-  def apply(name: String,
-            unit: String,
-            costPolicy: DSLCostPolicy,
-            isComplex: Boolean = false,
-            descriminatorField: String = "instanceId") =
+  def apply(name: String, unit: String, chargingBehavior: ChargingBehavior) = {
+    new ResourceSim(name, unit, chargingBehavior)
+  }
 
-    new ResourceSim(name, unit, costPolicy, isComplex, descriminatorField)
 }
index 05716bb..c722649 100644 (file)
@@ -34,7 +34,8 @@
  */
 
 package gr.grnet.aquarium.simulation
-import gr.grnet.aquarium.logic.accounting.dsl.{DSLCostPolicy, DSLPolicy, DiscreteCostPolicy}
+import gr.grnet.aquarium.policy.PolicyModel
+import gr.grnet.aquarium.charging.{DiscreteChargingBehavior, ChargingBehavior}
 
 
 /**
@@ -43,16 +44,11 @@ import gr.grnet.aquarium.logic.accounting.dsl.{DSLCostPolicy, DSLPolicy, Discret
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-class StdBandwidthResourceSim(name: String = StdVMTimeResourceSim.DSLNames.name,
-                              unit: String = StdVMTimeResourceSim.DSLNames.unit,
-                              costPolicy: DSLCostPolicy = DiscreteCostPolicy,
-                              isComplex: Boolean = false,
-                              descriminatorField: String = StdDiskspaceResourceSim.DSLNames.descriminatorField)
-extends ResourceSim(name,
-                    unit,
-                    costPolicy,
-                    isComplex,
-                    descriminatorField) {
+class StdBandwidthResourceSim(
+    name: String = StdVMTimeResourceSim.DSLNames.name,
+    unit: String = StdVMTimeResourceSim.DSLNames.unit,
+    costPolicy: ChargingBehavior = DiscreteChargingBehavior
+) extends ResourceSim(name, unit, costPolicy) {
 
 override def newInstance(instanceId: String, owner: UserSim, client: ClientSim) =
     StdBandwidthInstanceSim(this, instanceId, owner, client)
@@ -63,17 +59,15 @@ object StdBandwidthResourceSim {
   object DSLNames {
     final val name = "bandwidth"
     final val unit = "MB/Hr"
-    final val descriminatorField = "instanceId"
   }
 
-  def fromPolicy(dslPolicy: DSLPolicy): StdBandwidthResourceSim = {
-    val dslResource = dslPolicy.findResource(DSLNames.name).get
+  def fromPolicy(policy: PolicyModel): StdBandwidthResourceSim = {
+    val resourceType = policy.resourceTypesMap(DSLNames.name)
     new StdBandwidthResourceSim(
-      dslResource.name,
-      dslResource.unit,
-      dslResource.costPolicy,
-      dslResource.isComplex,
-      dslResource.descriminatorField)
+      resourceType.name,
+      resourceType.unit,
+      resourceType.chargingBehavior
+    )
   }
 }
 
index a37e634..3abe3e8 100644 (file)
@@ -35,9 +35,8 @@
 
 package gr.grnet.aquarium.simulation
 
-import gr.grnet.aquarium.logic.accounting.dsl.{DSLPolicy, ContinuousCostPolicy, DSLCostPolicy}
-import gr.grnet.aquarium.util.{ContextualLogger, Loggable}
-
+import gr.grnet.aquarium.policy.PolicyModel
+import gr.grnet.aquarium.charging.{ContinuousChargingBehavior, ChargingBehavior}
 
 /**
  * A simulator for the standard `diskspace` resource.
@@ -45,16 +44,11 @@ import gr.grnet.aquarium.util.{ContextualLogger, Loggable}
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-class StdDiskspaceResourceSim(name: String = StdVMTimeResourceSim.DSLNames.name,
-                              unit: String = StdVMTimeResourceSim.DSLNames.unit,
-                              costPolicy: DSLCostPolicy = ContinuousCostPolicy,
-                              isComplex: Boolean = false,
-                              descriminatorField: String = StdDiskspaceResourceSim.DSLNames.descriminatorField)
-  extends ResourceSim(name,
-                      unit,
-                      costPolicy,
-                      isComplex,
-                      descriminatorField) {
+class StdDiskspaceResourceSim(
+    name: String = StdVMTimeResourceSim.DSLNames.name,
+    unit: String = StdVMTimeResourceSim.DSLNames.unit,
+    chargingBehavior: ChargingBehavior = ContinuousChargingBehavior
+) extends ResourceSim(name, unit, chargingBehavior) {
 
   override def newInstance(instanceId: String, owner: UserSim, client: ClientSim) =
     StdDiskspaceInstanceSim(this, instanceId, owner, client)
@@ -65,16 +59,11 @@ object StdDiskspaceResourceSim {
   object DSLNames {
     final val name = "diskspace"
     final val unit = "MB/Hr"
-    final val descriminatorField = "instanceId"
   }
 
-  def fromPolicy(dslPolicy: DSLPolicy): StdDiskspaceResourceSim = {
-    val dslResource = dslPolicy.findResource(DSLNames.name).get
-    new StdDiskspaceResourceSim(
-      dslResource.name,
-      dslResource.unit,
-      dslResource.costPolicy,
-      dslResource.isComplex,
-      dslResource.descriminatorField)
+  def fromPolicy(policy: PolicyModel): StdDiskspaceResourceSim = {
+    val resourceType = policy.resourceTypesMap(DSLNames.name)
+
+    new StdDiskspaceResourceSim(resourceType.name, resourceType.unit)
   }
 }
index f309eaa..81086df 100644 (file)
 
 package gr.grnet.aquarium.simulation
 
-import gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicyValues
 import java.util.Date
 import gr.grnet.aquarium.util.date.MutableDateCalc
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
+import gr.grnet.aquarium.charging.OnOffChargingBehaviorValues
 
 /**
  * A simulator for an instance of the standard `vmtime` resource.
@@ -46,31 +46,38 @@ import gr.grnet.aquarium.event.model.resource.ResourceEventModel
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-case class StdVMTimeInstanceSim(override val resource: StdVMTimeResourceSim,
-                                override val instanceId: String,
-                                override val owner: UserSim,
-                                override val client: ClientSim)
-extends ResourceInstanceSim(resource, instanceId, owner, client) {
+case class StdVMTimeInstanceSim(
+    override val resource: StdVMTimeResourceSim,
+    override val instanceId: String,
+    override val owner: UserSim,
+    override val client: ClientSim
+) extends ResourceInstanceSim(resource, instanceId, owner, client) {
+
+  def newON(
+      occurredDate: Date,
+      details: Map[String, String] = Map(),
+      eventVersion: String = "1.0"
+  ) = {
 
-  def newON(occurredDate: Date,
-            details: Map[String, String] = Map(),
-            eventVersion: String = "1.0") = {
     newResourceEvent(
       occurredDate.getTime,
       occurredDate.getTime,
-      OnOffCostPolicyValues.ON,
+      OnOffChargingBehaviorValues.ON,
       details,
       eventVersion
     )
   }
 
-  def newOFF(occurredDate: Date,
-             details: Map[String, String] = Map(),
-             eventVersion: String = "1.0") = {
+  def newOFF(
+      occurredDate: Date,
+      details: Map[String, String] = Map(),
+      eventVersion: String = "1.0"
+  ) = {
+
     newResourceEvent(
       occurredDate.getTime,
       occurredDate.getTime,
-      OnOffCostPolicyValues.OFF,
+      OnOffChargingBehaviorValues.OFF,
       details,
       eventVersion
     )
@@ -84,10 +91,12 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
     (onID, offID)
   }
 
-  def newOFF_OutOfSync(occuredDate: Date,
-                       outOfSyncHours: Int,
-                       details: Map[String, String] = Map(),
-                       eventVersion: String = "1.0") = {
+  def newOFF_OutOfSync(
+      occuredDate: Date,
+      outOfSyncHours: Int,
+      details: Map[String, String] = Map(),
+      eventVersion: String = "1.0"
+  ) = {
 
     val occurredDateCalc = new MutableDateCalc(occuredDate)
     val occurredTime = occurredDateCalc.toMillis
@@ -96,7 +105,7 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
     newResourceEvent(
       occurredTime,
       receivedTime,
-      OnOffCostPolicyValues.OFF,
+      OnOffChargingBehaviorValues.OFF,
       details,
       eventVersion
     )
index 3bf6e25..d15e18b 100644 (file)
@@ -35,7 +35,8 @@
 
 package gr.grnet.aquarium.simulation
 
-import gr.grnet.aquarium.logic.accounting.dsl.{DSLPolicy, OnOffCostPolicy, DSLCostPolicy}
+import gr.grnet.aquarium.policy.PolicyModel
+import gr.grnet.aquarium.charging.{OnOffChargingBehavior, ChargingBehavior}
 
 
 /**
@@ -44,16 +45,11 @@ import gr.grnet.aquarium.logic.accounting.dsl.{DSLPolicy, OnOffCostPolicy, DSLCo
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-class StdVMTimeResourceSim(name: String = StdVMTimeResourceSim.DSLNames.name,
-                           unit: String = StdVMTimeResourceSim.DSLNames.unit,
-                           costPolicy: DSLCostPolicy = OnOffCostPolicy,
-                           isComplex: Boolean = true,
-                           descriminatorField: String = StdVMTimeResourceSim.DSLNames.descriminatorField)
-  extends ResourceSim(name,
-                      unit,
-                      costPolicy,
-                      isComplex,
-                      descriminatorField) {
+class StdVMTimeResourceSim(
+    name: String = StdVMTimeResourceSim.DSLNames.name,
+    unit: String = StdVMTimeResourceSim.DSLNames.unit,
+    chargingBehavior: ChargingBehavior = OnOffChargingBehavior
+) extends ResourceSim(name, unit, chargingBehavior) {
 
   override def newInstance(instanceId: String, owner: UserSim, client: ClientSim) =
     StdVMTimeInstanceSim(this, instanceId, owner, client)
@@ -64,16 +60,11 @@ object StdVMTimeResourceSim {
   object DSLNames {
     final val name = "vmtime"
     final val unit = "Hr"
-    final val descriminatorField = "vmtime"
   }
 
-  def fromPolicy(dslPolicy: DSLPolicy): StdVMTimeResourceSim = {
-    val dslResource = dslPolicy.findResource(DSLNames.name).get
-    new StdVMTimeResourceSim(
-      dslResource.name,
-      dslResource.unit,
-      dslResource.costPolicy,
-      dslResource.isComplex,
-      dslResource.descriminatorField)
+  def fromPolicy(policy: PolicyModel): StdVMTimeResourceSim = {
+    val resourceType = policy.resourceTypesMap(DSLNames.name)
+
+    new StdVMTimeResourceSim(resourceType.name, resourceType.unit)
   }
 }
\ No newline at end of file
index 572f6fa..7e41a9d 100644 (file)
 
 package gr.grnet.aquarium.store
 
-import scala.collection.immutable
 import collection.immutable.SortedMap
-import gr.grnet.aquarium.logic.accounting.dsl.{DSL, DSLPolicy, Timeslot}
-import com.ckkloverdos.maybe.Maybe
-import gr.grnet.aquarium.event.model.PolicyEntry
+import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
+import gr.grnet.aquarium.policy.PolicyModel
 
 /**
- * A store for serialized policy entries.
+ * A store for serialized policy models.
  *
  * @author Georgios Gousios <gousiosg@gmail.com>
+ * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 trait PolicyStore {
+  type Policy <: PolicyModel
 
   /**
    * Load all accounting policies valid after the specified time instance.
    * The results are returned sorted by PolicyEntry.validFrom
    */
-  def loadPolicyEntriesAfter(after: Long): List[PolicyEntry]
+  def loadPoliciesAfter(afterMillis: Long): List[Policy]
 
-  def loadAndSortPolicyEntriesWithin(fromMillis: Long, toMillis: Long): SortedMap[Timeslot, PolicyEntry] = {
-    val all = loadPolicyEntriesAfter(0L)
-    val filtered = all.filter { policyEntry ⇒
-      policyEntry.validFrom <= fromMillis &&
-      policyEntry.validTo   >= toMillis
-    }
-
-    (immutable.SortedMap[Timeslot, PolicyEntry]() /: filtered) { (map, policyEntry) ⇒
-      map.updated(policyEntry.fromToTimeslot, policyEntry)
-    }
-  }
-  
-  def loadAndSortPoliciesWithin(fromMillis: Long, toMillis: Long, dsl: DSL): SortedMap[Timeslot, DSLPolicy] = {
-    for((timeslot, policyEntry) <- loadAndSortPolicyEntriesWithin(fromMillis, toMillis))
-      yield (timeslot, dsl.parse(policyEntry.policyYAML))
-  }
-  
-  def loadValidPolicyEntryAt(atMillis: Long): Option[PolicyEntry] = {
-    loadPolicyEntriesAfter(0L).find { policyEntry ⇒
-      policyEntry.fromToTimeslot.containsTimeInMillis(atMillis)
-    }
+  def loadAndSortPoliciesWithin(fromMillis: Long, toMillis: Long): SortedMap[Timeslot, Policy] = {
+    // FIXME implement
+    throw new UnsupportedOperationException
   }
   
-  def loadValidPolicyAt(atMillis: Long, dsl: DSL): Option[DSLPolicy] = {
-    loadValidPolicyEntryAt(atMillis).map(policyEntry ⇒ dsl.parse(policyEntry.policyYAML))
+  def loadValidPolicyAt(atMillis: Long): Option[Policy] = {
+    // FIXME implement
+    throw new UnsupportedOperationException
   }
 
   /**
    * Store an accounting policy.
    */
-  def storePolicyEntry(policy: PolicyEntry): Maybe[RecordID]
-
-  /**
-   * Updates the policy record whose id is equal to the id
-   * of the provided policy entry.
-   */
-  def updatePolicyEntry(policy: PolicyEntry): Unit
+  def insertPolicy(policy: PolicyModel): Policy
 
   /**
-   * Find a policy by its unique id
+   * Find a policy by its unique id.
    */
-  def findPolicyEntry(id: String): Option[PolicyEntry]
+  def findPolicyByID(id: String): Option[Policy]
 }
\ No newline at end of file
index 405bede..fb21af0 100644 (file)
@@ -42,13 +42,13 @@ import scala.collection.JavaConversions._
 import collection.mutable.ConcurrentMap
 import java.util.concurrent.ConcurrentHashMap
 import gr.grnet.aquarium.Configurable
-import gr.grnet.aquarium.event.model.PolicyEntry
 import gr.grnet.aquarium.event.model.im.{StdIMEvent, IMEventModel}
 import org.bson.types.ObjectId
 import gr.grnet.aquarium.event.model.resource.{StdResourceEvent, ResourceEventModel}
 import gr.grnet.aquarium.computation.state.UserState
 import gr.grnet.aquarium.util.Tags
 import gr.grnet.aquarium.computation.BillingMonthInfo
+import gr.grnet.aquarium.policy.StdPolicy
 
 /**
  * An implementation of various stores that persists parts in memory.
@@ -59,16 +59,20 @@ import gr.grnet.aquarium.computation.BillingMonthInfo
  * @author Georgios Gousios <gousiosg@gmail.com>
  */
 
-class MemStoreProvider extends UserStateStore
-  with Configurable with PolicyStore
-  with ResourceEventStore with IMEventStore
-  with StoreProvider {
+class MemStoreProvider
+extends StoreProvider
+   with UserStateStore
+   with Configurable
+   with PolicyStore
+   with ResourceEventStore
+   with IMEventStore {
 
   override type IMEvent = MemIMEvent
   override type ResourceEvent = MemResourceEvent
+  override type Policy = StdPolicy
 
-  private[this] var _userStates     = List[UserState]()
-  private[this] var _policyEntries  = List[PolicyEntry]()
+  private[this] var _userStates = List[UserState]()
+  private[this] var _policies  = List[Policy]()
   private[this] var _resourceEvents = List[ResourceEvent]()
 
   private[this] val imEventById: ConcurrentMap[String, MemIMEvent] = new ConcurrentHashMap[String, MemIMEvent]()
@@ -84,7 +88,7 @@ class MemStoreProvider extends UserStateStore
       Tags.UserStateTag     -> _userStates.size,
       Tags.ResourceEventTag -> _resourceEvents.size,
       Tags.IMEventTag       -> imEventById.size,
-      "PolicyEntry"         -> _policyEntries.size
+      "PolicyEntry"         -> _policies.size
     )
 
     "MemStoreProvider(%s)" format map
@@ -258,23 +262,12 @@ class MemStoreProvider extends UserStateStore
   }
   //- IMEventStore
 
-  def loadPolicyEntriesAfter(after: Long) =
-    _policyEntries.filter(p => p.validFrom > after)
+  def loadPoliciesAfter(afterMillis: Long) =
+    _policies.filter(p => p.validFrom > afterMillis)
             .sortWith((a,b) => a.validFrom < b.validFrom)
 
-  def storePolicyEntry(policy: PolicyEntry) = {_policyEntries = policy :: _policyEntries; Just(RecordID(policy.id))}
-
-  def updatePolicyEntry(policy: PolicyEntry) =
-    _policyEntries = _policyEntries.foldLeft(List[PolicyEntry]()){
-      (acc, p) =>
-        if (p.id == policy.id)
-          policy :: acc
-        else
-          p :: acc
-  }
-
-  def findPolicyEntry(id: String) = {
-    _policyEntries.find(p => p.id == id)
+  def findPolicyByID(id: String) = {
+    _policies.find(p => p.id == id)
   }
 }
 
  * or implied, of GRNET S.A.
  */
 
-package gr.grnet.aquarium.logic.accounting.dsl
-
-import gr.grnet.aquarium.util.json.JsonSupport
+package gr.grnet.aquarium.store.mongodb
 
+import gr.grnet.aquarium.Timespan
+import gr.grnet.aquarium.policy.{PolicyModel, FullPriceTable, ResourceType}
 
 /**
- * Enumerates known resources by name.
- *
- * This is related to [[gr.grnet.aquarium.logic.accounting.dsl.DSLResource]] but currently does not directly appear
- * in the rest of the DSL.
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-final case class DSLResourcesMap(underlying: Map[String, DSLResource]) extends JsonSupport {
-  def this(list: List[DSLResource]) = this(Map(list.map(r ⇒ (r.name, r)): _*))
+case class MongoDBPolicy(
+    _id: String,
+    id: String,
+    parentID: Option[String],
+    validityTimespan: Timespan,
+    resourceTypes: Set[ResourceType],
+    chargingBehaviorClasses: Set[String],
+    roleMapping: Map[String/*Role*/, FullPriceTable]
+) extends PolicyModel {
 
-  def map   = underlying
-  def names = underlying.keySet
+  def idInStore = Some(_id)
+}
 
-  def findResource(name: String): Option[DSLResource] = {
-    underlying.get(name)
+object MongoDBPolicy {
+  final def fromOther(policy: PolicyModel, _id: String): MongoDBPolicy = {
+    MongoDBPolicy(
+      _id,
+      policy.id,
+      policy.parentID,
+      policy.validityTimespan,
+      policy.resourceTypes,
+      policy.chargingBehaviorClasses,
+      policy.roleMapping
+    )
   }
-
-  def toResourcesList: List[DSLResource] = underlying.valuesIterator.toList
 }
index 4cc3853..61e53db 100644 (file)
@@ -44,17 +44,15 @@ import gr.grnet.aquarium.event.model.im.IMEventModel.{Names ⇒ IMEventNames}
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
 import gr.grnet.aquarium.event.model.resource.ResourceEventModel.{Names ⇒ ResourceEventNames}
 import gr.grnet.aquarium.store._
-import gr.grnet.aquarium.event.model.PolicyEntry.{JsonNames ⇒ PolicyJsonNames}
-import gr.grnet.aquarium.logic.accounting.Policy
 import com.mongodb._
 import org.bson.types.ObjectId
-import com.ckkloverdos.maybe.Maybe
 import gr.grnet.aquarium.util._
 import gr.grnet.aquarium.converter.Conversions
 import gr.grnet.aquarium.computation.state.UserState
-import gr.grnet.aquarium.event.model.{ExternalEventModel, PolicyEntry}
+import gr.grnet.aquarium.event.model.ExternalEventModel
 import gr.grnet.aquarium.computation.BillingMonthInfo
-import gr.grnet.aquarium.Aquarium
+import gr.grnet.aquarium.policy.PolicyModel
+import gr.grnet.aquarium.{Aquarium, AquariumException}
 
 /**
  * Mongodb implementation of the various aquarium stores.
@@ -63,6 +61,7 @@ import gr.grnet.aquarium.Aquarium
  * @author Georgios Gousios <gousiosg@gmail.com>
  */
 class MongoDBStore(
+    val aquarium: Aquarium,
     val mongo: Mongo,
     val database: String,
     val username: String,
@@ -75,28 +74,22 @@ class MongoDBStore(
 
   override type IMEvent = MongoDBIMEvent
   override type ResourceEvent = MongoDBResourceEvent
+  override type Policy = MongoDBPolicy
 
-  private[store] lazy val resourceEvents   = getCollection(MongoDBStore.RESOURCE_EVENTS_COLLECTION)
-  private[store] lazy val userStates       = getCollection(MongoDBStore.USER_STATES_COLLECTION)
-  private[store] lazy val imEvents         = getCollection(MongoDBStore.IM_EVENTS_COLLECTION)
-  private[store] lazy val unparsedIMEvents = getCollection(MongoDBStore.UNPARSED_IM_EVENTS_COLLECTION)
-  private[store] lazy val policyEntries    = getCollection(MongoDBStore.POLICY_ENTRIES_COLLECTION)
+  private[store] lazy val resourceEvents = getCollection(MongoDBStore.RESOURCE_EVENTS_COLLECTION)
+  private[store] lazy val userStates = getCollection(MongoDBStore.USER_STATES_COLLECTION)
+  private[store] lazy val imEvents = getCollection(MongoDBStore.IM_EVENTS_COLLECTION)
+  private[store] lazy val policies = getCollection(MongoDBStore.POLICY_COLLECTION)
 
   private[this] def getCollection(name: String): DBCollection = {
     val db = mongo.getDB(database)
     //logger.debug("Authenticating to mongo")
     if(!db.isAuthenticated && !db.authenticate(username, password.toCharArray)) {
-      throw new StoreException("Could not authenticate user %s".format(username))
+      throw new AquariumException("Could not authenticate user %s".format(username))
     }
     db.getCollection(name)
   }
 
-  private[this] def _sortByTimestampAsc[A <: ExternalEventModel](one: A, two: A): Boolean = {
-    if (one.occurredMillis > two.occurredMillis) false
-    else if (one.occurredMillis < two.occurredMillis) true
-    else true
-  }
-
   //+ResourceEventStore
   def createResourceEventFromOther(event: ResourceEventModel): ResourceEvent = {
     MongoDBResourceEvent.fromOther(event, null)
@@ -169,7 +162,7 @@ class MongoDBStore(
 
   //+ UserStateStore
   def insertUserState(userState: UserState) = {
-    MongoDBStore.insertUserState(
+    MongoDBStore.insertObject(
       userState.copy(_id = new ObjectId().toString),
       userStates,
       MongoDBStore.jsonSupportToDBObject
@@ -267,26 +260,24 @@ class MongoDBStore(
 
 
   //+PolicyStore
-  def loadPolicyEntriesAfter(after: Long): List[PolicyEntry] = {
-    val query = new BasicDBObject(PolicyEntry.JsonNames.validFrom,
-      new BasicDBObject("$gt", after))
-    MongoDBStore.runQuery(query, policyEntries)(MongoDBStore.dbObjectToPolicyEntry)(Some(_sortByTimestampAsc))
+  def loadPoliciesAfter(after: Long): List[Policy] = {
+    // FIXME implement
+    throw new UnsupportedOperationException
   }
 
-  def storePolicyEntry(policy: PolicyEntry): Maybe[RecordID] = MongoDBStore.storePolicyEntry(policy, policyEntries)
 
-
-  def updatePolicyEntry(policy: PolicyEntry) = {
-    //Find the entry
-    val query = new BasicDBObject(PolicyEntry.JsonNames.id, policy.id)
-    val policyObject = MongoDBStore.jsonSupportToDBObject(policy)
-    policyEntries.update(query, policyObject, true, false)
-  }
-  
-  def findPolicyEntry(id: String) = {
-    MongoDBStore.findBy(PolicyJsonNames.id, id, policyEntries, MongoDBStore.dbObjectToPolicyEntry)
+  def findPolicyByID(id: String) = {
+    // FIXME implement
+    throw new UnsupportedOperationException
   }
 
+  /**
+   * Store an accounting policy.
+   */
+  def insertPolicy(policy: PolicyModel): Policy = {
+    val dbPolicy = MongoDBPolicy.fromOther(policy, new ObjectId().toStringMongod)
+    MongoDBStore.insertObject(dbPolicy, policies, MongoDBStore.jsonSupportToDBObject)
+  }
   //-PolicyStore
 }
 
@@ -318,23 +309,9 @@ object MongoDBStore {
   final val IM_EVENTS_COLLECTION = "imevents"
 
   /**
-   * Collection holding [[gr.grnet.aquarium.event.model.im.IMEventModel]]s that could not be parsed to normal objects.
-   *
-   * We of course assume at least a valid JSON representation.
-   *
-   * User events are coming from the IM module (external).
-   */
-  final val UNPARSED_IM_EVENTS_COLLECTION = "unparsed_imevents"
-
-  /**
-   * Collection holding [[gr.grnet.aquarium.logic.accounting.dsl.DSLPolicy]].
-   */
-//  final val POLICIES_COLLECTION = "policies"
-
-  /**
-   * Collection holding [[gr.grnet.aquarium.event.model.PolicyEntry]].
+   * Collection holding [[gr.grnet.aquarium.policy.PolicyModel]]s.
    */
-  final val POLICY_ENTRIES_COLLECTION = "policyEntries"
+  final val POLICY_COLLECTION = "policies"
 
   def dbObjectToUserState(dbObj: DBObject): UserState = {
     UserState.fromJson(JSON.serialize(dbObj))
@@ -350,10 +327,6 @@ object MongoDBStore {
     }
   }
 
-  def dbObjectToPolicyEntry(dbObj: DBObject): PolicyEntry = {
-    PolicyEntry.fromJson(JSON.serialize(dbObj))
-  }
-
   def ping(mongo: Mongo): Unit = synchronized {
     // This requires a network roundtrip
     mongo.isLocked
@@ -406,10 +379,6 @@ object MongoDBStore {
   def storeUserState(userState: UserState, collection: DBCollection) = {
     storeAny[UserState](userState, collection, ResourceEventNames.userID, _.userID, MongoDBStore.jsonSupportToDBObject)
   }
-  
-  def storePolicyEntry(policyEntry: PolicyEntry, collection: DBCollection): Maybe[RecordID] = {
-    Maybe(storeAny[PolicyEntry](policyEntry, collection, PolicyJsonNames.id, _.id, MongoDBStore.jsonSupportToDBObject))
-  }
 
   def storeAny[A](any: A,
                   collection: DBCollection,
@@ -426,43 +395,11 @@ object MongoDBStore {
     RecordID(dbObject.get("_id").toString)
   }
 
-  // FIXME: consolidate
-  def insertUserState[A <: UserState](obj: A, collection: DBCollection, serializer: A ⇒ DBObject) = {
-    val dbObject = serializer apply obj
-    val objectId = obj._id  match {
-      case null ⇒
-        val _id = new ObjectId()
-        dbObject.put("_id", _id)
-        _id
-
-      case _id ⇒
-        _id
-    }
-
-    dbObject.put(JsonNames._id, objectId)
-
-    collection.insert(dbObject, WriteConcern.JOURNAL_SAFE)
-
+  def insertObject[A <: AnyRef](obj: A, collection: DBCollection, serializer: A ⇒ DBObject) : A = {
+    collection.insert(serializer apply obj, WriteConcern.JOURNAL_SAFE)
     obj
   }
 
-  def insertObject[A <: MongoDBEventModel](obj: A, collection: DBCollection, serializer: (A) => DBObject) : Unit = {
-    val dbObject = serializer apply obj
-    val objectId = obj._id  match {
-      case null ⇒
-        val _id = new ObjectId()
-        dbObject.put("_id", _id)
-        _id
-
-      case _id ⇒
-        _id
-    }
-
-    dbObject.put(JsonNames._id, objectId)
-
-    collection.insert(dbObject, WriteConcern.JOURNAL_SAFE)
-  }
-
   def jsonSupportToDBObject(jsonSupport: JsonSupport) = {
     Conversions.jsonSupportToDBObject(jsonSupport)
   }
index 1efb062..ccaec54 100644 (file)
@@ -38,44 +38,80 @@ package gr.grnet.aquarium.store.mongodb
 import com.ckkloverdos.props.Props
 import com.mongodb.{MongoException, Mongo, MongoOptions, ServerAddress}
 import gr.grnet.aquarium.store._
-import gr.grnet.aquarium.{AquariumException, Configurable}
+import gr.grnet.aquarium.{AquariumAwareSkeleton, AquariumException, Configurable}
+import gr.grnet.aquarium.service.event.AquariumCreatedEvent
+import com.google.common.eventbus.Subscribe
+import com.ckkloverdos.key.{IntKey, StringKey}
+import gr.grnet.aquarium.util.Loggable
 
 /**
  *
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-class MongoDBStoreProvider extends StoreProvider with Configurable {
-  private[this] var _mongo: Mongo = _
-  private[this] var _database: String = _
-  private[this] var _username: String = _
-  private[this] var _password: String = _
+class MongoDBStoreProvider extends StoreProvider with Configurable with Loggable with AquariumAwareSkeleton {
+  private case class ConnectionData(
+      database: String,
+      host: String,
+      port: Int,
+      username: String,
+      password: String,
+      connectionsPerHost: Int,
+      threadsAllowedToBlockForConnectionMultiplier: Int
+  )
 
+  private[this] var _mongo: Mongo = _
+  private[this] var _connectionData: ConnectionData = _
   private[this] var _mongoDBStore: MongoDBStore = _
 
-  def propertyPrefix = Some(MongoDBStoreProvider.MongoDBKeys.Prefix)
+  def propertyPrefix = Some(MongoDBStoreProvider.Prefix)
 
   def configure(props: Props) = {
-    import MongoDBStoreProvider.MongoDBKeys
+    import MongoDBStoreProvider.EnvKeys
+
+    this._connectionData = ConnectionData(
+      database = props.getEx(EnvKeys.mongodbDatabase.name),
+      host =  props.getEx(EnvKeys.mongodbHost.name),
+      port = props.getIntEx(EnvKeys.mongodbPort.name),
+      username = props.getEx(EnvKeys.mongodbUsername.name),
+      password = props.getEx(EnvKeys.mongodbPassword.name),
+      connectionsPerHost = props.getInt(EnvKeys.mongodbConnectionsPerHost.name).getOr(20),
+      threadsAllowedToBlockForConnectionMultiplier = props.getInt(
+        EnvKeys.mongodbThreadsAllowedToBlockForConnectionMultiplier.name).getOr(5)
+    )
+  }
 
-    this._database = props.getEx(MongoDBKeys.dbschema)
-    this._username = props.getEx(MongoDBKeys.username)
-    this._password = props.getEx(MongoDBKeys.password)
-    val host = props.getEx(MongoDBKeys.host)
-    val port = props.getEx(MongoDBKeys.port).toInt
+  @Subscribe
+  override def awareOfAquarium(event: AquariumCreatedEvent) {
+    super.awareOfAquarium(event)
 
+    doSetup()
+  }
+
+  private def doSetup() {
     try {
-      val addr = new ServerAddress(host, port)
+      val host = this._connectionData.host
+      val port = this._connectionData.port
+      val serverAddress = new ServerAddress(host, port)
 
       val opt = new MongoOptions()
-      opt.connectionsPerHost = props.getEx(MongoDBKeys.connection_pool_size).toInt
-      opt.threadsAllowedToBlockForConnectionMultiplier = 8
-
-      this._mongo = new Mongo(addr, opt)
-      this._mongoDBStore = new MongoDBStore(this._mongo, this._database, this._username, this._password)
+      opt.connectionsPerHost = this._connectionData.connectionsPerHost
+      opt.threadsAllowedToBlockForConnectionMultiplier = this._connectionData.threadsAllowedToBlockForConnectionMultiplier
+
+      this._mongo = new Mongo(serverAddress, opt)
+      this._mongoDBStore = new MongoDBStore(
+        aquarium,
+        this._mongo,
+        this._connectionData.database,
+        this._connectionData.username,
+        this._connectionData.password
+      )
     } catch {
-      case e: MongoException =>
-        throw new AquariumException("Cannot connect to mongo at %s:%s".format(host, port), e)
+      case e: MongoException ⇒
+        throw new AquariumException("While connecting to MongoDB using %s".format(this._connectionData), e)
+
+      case e: Exception ⇒
+        throw new AquariumException("While connecting to MongoDB using %s".format(this._connectionData), e)
     }
   }
 
@@ -91,47 +127,36 @@ class MongoDBStoreProvider extends StoreProvider with Configurable {
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 object MongoDBStoreProvider {
+  final val Prefix = "mongodb"
+  final val PrefixAndDot = Prefix + "."
 
-  /**
-   * Note that these keys must be prefixed by `mongodb` in the configuration file
-   *
-   * @author Christos KK Loverdos <loverdos@gmail.com>
-   */
-  object MongoDBKeys {
-    final val Prefix = "mongodb"
-    final val PrefixAndDot = Prefix + "."
-
-    private[this] def p(name: String) = PrefixAndDot + name
-
+  object EnvKeys {
     /**
      * Hostname for the MongoDB
      */
-    final val host = p("host")
+    final val mongodbHost = StringKey(PrefixAndDot + "host")
 
-    /**
-     * Username for connecting to the MongoDB
-     */
-    final val username = p("username")
 
-    /**
-     *  Password for connecting to the MongoDB
-     */
-    final val password = p("password")
+    final val mongodbPort     = IntKey   (PrefixAndDot + "port")
 
     /**
-     *  Password for connecting to the MongoDB
+     * Username for connecting to the MongoDB.
      */
-    final val port = p("port")
+    final val mongodbUsername = StringKey(PrefixAndDot + "username")
 
     /**
-     *  The DB schema to use
+     *  Password for connecting to the MongoDB.
      */
-    final val dbschema = p("dbschema")
+    final val mongodbPassword = StringKey(PrefixAndDot + "password")
 
     /**
-     * Maximum number of open connections to MongoDB
+     *  The MongoDB database to use.
      */
-    final val connection_pool_size = p("connection.pool.size")
+    final val mongodbDatabase = StringKey(PrefixAndDot + "database")
+
+    final val mongodbConnectionsPerHost = IntKey(PrefixAndDot + "connections.per.host")
 
+    final val mongodbThreadsAllowedToBlockForConnectionMultiplier =
+      IntKey("threads.allowed.to.block.for.connection.multiplier")
   }
 }
\ No newline at end of file
diff --git a/src/main/scala/gr/grnet/aquarium/util/CollectionUtils.scala b/src/main/scala/gr/grnet/aquarium/util/CollectionUtils.scala
deleted file mode 100644 (file)
index c2db930..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util
-
-import java.util.{Map => JMap,
-                  List => JList,
-                  HashMap => JHashMap,
-                  ArrayList => JArrayList}
-
-/**
- * Utility functions for Collections, including recursive conversion to Java
- * for Maps and Lists
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-trait CollectionUtils {
-
-  /**Merge input maps on a field by field basis. In case of duplicate keys
-   *  values from the first map are prefered.
-   */
-  private 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))
-    }
-  }
-
-  /**Merge input maps on a field by field basis. In case of duplicate keys,
-   *  the provided function is used to determine which value to keep in the
-   *  merged map.
-   */
-  private def mergeMaps[A, B](ms: List[Map[A, B]])(f: (B, B) => B): Map[A, B] =
-    (Map[A, B]() /: (for (m <- ms; kv <- m) yield kv)) {
-      (a, kv) =>
-        a + (if (a.contains(kv._1))
-          kv._1 -> f(a(kv._1), kv._2)
-        else kv)
-    }
-
-
-  /**
-   * Recursively convert a Scala[String, Any] map to a Java equivalent.
-   * It will also convert values that are Scala Maps or Lists or Seqs
-   * to Java equivalents.
-   */
-  def mapToJavaMap(map: Map[String, Any]): JMap[String, Object] = {
-    val result = new JHashMap[String, Object]
-
-    map.foreach(kv => result.put(kv._1, transformValue(kv._2)))
-    result
-  }
-
-  /**
-   * Recursively convert a Scala List[Any] map to a Java equivalent
-   * List[Object]. If the list's items are of type List[_]
-   * and/or Map[String, Any] those will also be converted to
-   * Java equivalents.
-   */
-  def listToJavaList(seq: List[Any]): JList[Object] = {
-    val list = new JArrayList[Object]
-    seq.foreach(a => list.add(transformValue(a)))
-    list
-  }
-
-  private def transformValue(v: Any) = {
-    val v2  = v match {
-      case l: List[_]     => listToJavaList(l)
-      case s: Seq[_]      => listToJavaList(s.toList)
-      case i: Iterator[_] => listToJavaList(i.toList)
-      case m: Map[String, Any] => mapToJavaMap(m)
-      case _              => v
-    }
-
-    v2.asInstanceOf[Object]
-  }
-}
\ No newline at end of file
diff --git a/src/main/scala/gr/grnet/aquarium/util/DateUtils.scala b/src/main/scala/gr/grnet/aquarium/util/DateUtils.scala
deleted file mode 100644 (file)
index fbef64f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util
-
-import scala.collection.mutable
-import java.util.{Calendar, Date, GregorianCalendar}
-import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
-
-/**
- * Various utils for manipulating dates, with special
- * emphasis on credit DSL requirements.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-trait DateUtils extends Loggable {
-
-  /**
-   * Returns a date that is equal to the latest of
-   * (`d - 1 year`, `limit`)
-   */
-  def oneYearBack(d: Date, limit: Date): Date = {
-    val c = new GregorianCalendar()
-    c.setTime(d)
-    c.add(Calendar.YEAR, -1)
-    if (c.getTime.before(limit))
-      limit
-    else
-      c.getTime
-  }
-
-  /**
-   * Returns a date that is equal to the earliest of
-   * (`d + 1 year`, `limit`)
-   */
-  def oneYearAhead(d: Date, limit: Date): Date = {
-    val c = new GregorianCalendar()
-    c.setTime(d)
-    c.add(Calendar.YEAR, 1)
-    if (c.getTime.before(limit))
-      c.getTime
-    else
-      limit
-  }
-}
index c72e55f..bdb01c6 100644 (file)
@@ -35,7 +35,6 @@
 
 package gr.grnet.aquarium.util.xstream
 
-import com.thoughtworks.xstream.XStream
 import com.thoughtworks.xstream.converters.{MarshallingContext, UnmarshallingContext}
 import com.thoughtworks.xstream.io.{HierarchicalStreamWriter, HierarchicalStreamReader}
 import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter
diff --git a/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLBooleanNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLBooleanNode.scala
deleted file mode 100644 (file)
index 91085e7..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * A boolean node
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-
-case class YAMLBooleanNode(path: String,  bool: Boolean) extends YAMLNode {
-  def /(childName: String) = YAMLEmptyNode
-
-  override def booleanValue = bool
-
-  override def isBoolean = false
-
-  def withPath(newPath: String) = this.copy(path = newPath)
-}
\ No newline at end of file
diff --git a/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLDoubleNode.scala
deleted file mode 100644 (file)
index c603f31..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * 
- * @author Georgios Gousios <gousiosg@gmail.com>.
- */
-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/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLEmptyNode.scala
deleted file mode 100644 (file)
index fd3c198..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * 
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case object YAMLEmptyNode extends YAMLNode {
-  def /(childName: String) = YAMLEmptyNode
-
-  override def isEmpty = true
-
-  def path = ""
-  def withPath(newPath: String) = this
-}
-
diff --git a/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLHelpers.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLHelpers.scala
deleted file mode 100644 (file)
index 63093ec..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-import org.yaml.snakeyaml.Yaml
-import java.io.Reader
-import gr.grnet.aquarium.util.CollectionUtils
-
-/**
- * Utility methods for parsing YAML and conveniently returning `YAMLNode`s.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-object YAMLHelpers extends CollectionUtils {
-  def loadYAML(r: Reader, closeReader: Boolean = true): YAMLNode = {
-    val yaml = new Yaml()
-    val loaded = yaml.load(r)
-    if(closeReader) r.close()
-
-    YAMLNode(loaded)
-  }
-
-  def dumpYAML(yamlMap: Map[String, Any]): String = {
-    val yaml = new Yaml()
-    val jmap = mapToJavaMap(yamlMap)
-    yaml.dump(jmap)
-  }
-}
\ No newline at end of file
diff --git a/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLIntNode.scala
deleted file mode 100644 (file)
index ba73193..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * 
- * @author Georgios Gousios <gousiosg@gmail.com>.
- */
-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/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLListNode.scala
deleted file mode 100644 (file)
index 94131b4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * 
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class YAMLListNode(path: String,  list: List[YAMLNode]) extends YAMLNode {
-  def /(childName: String) = YAMLEmptyNode
-
-  override def listValue = list
-  override def isList = true
-
-  def head = list match {
-    case Nil    => YAMLEmptyNode
-    case h :: _ => h
-  }
-  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/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLMapNode.scala
deleted file mode 100644 (file)
index ea328ef..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-import collection.mutable
-
-/**
- * 
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class YAMLMapNode(path: String, map: mutable.Map[String, YAMLNode]) extends YAMLNode {
-  def /(childName: String) = map.get(childName) match {
-    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/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLNode.scala
deleted file mode 100644 (file)
index 5158310..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-import java.util.{Map => JMap, List => JList}
-import scala.collection.mutable
-import scala.collection.JavaConversions._
-
-
-/**
- * A representation of a parsed object that has originated in YAML format.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-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
-  def listValue: List[YAMLNode] = Nil
-  def mapValue: Map[String, YAMLNode] = Map()
-  def booleanValue = false
-  def longValue = 0L
-
-  def isEmpty = false
-
-  def isString = false
-  def isInt = false
-  def isDouble = false
-  def isLong = false
-  def isMap = false
-  def isList = false
-  def isBoolean = false
-  def isUnknown = false
-
-  def foreach[T](f: YAMLNode => T): Unit = {}
-}
-
-/**
- * Companion object.
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-object 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 javaMap: JMap[_, _] =>
-        val scalaMap: mutable.Map[String, AnyRef] = javaMap.asInstanceOf[JMap[String, AnyRef]]
-        val nodeMap = scalaMap map {
-          case (key, value) if value.isInstanceOf[YAMLNode] =>
-            val yvalue = value.asInstanceOf[YAMLNode]//.withPath(concatPaths(basePath, key))
-            (key, yvalue)
-          case (key, value) =>
-            (key, apply(value, concatPaths(basePath, key)))
-        }
-        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(basePath, string)
-      case x: YAMLNode => x
-      case int: java.lang.Integer =>
-        YAMLIntNode(basePath, int)
-      case double: java.lang.Double =>
-        YAMLDoubleNode(basePath, double)
-      case long: java.lang.Long =>
-        YAMLLongNode(basePath, long)
-      case x: java.lang.Boolean  =>
-        YAMLBooleanNode(basePath, x)
-      case obj =>
-        YAMLUnknownNode(obj, obj.getClass.getName)
-    }
-  }
-}
-
-
-
-
diff --git a/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLStringNode.scala
deleted file mode 100644 (file)
index 3890c8e..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * 
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-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/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala b/src/main/scala/gr/grnet/aquarium/util/yaml/YAMLUnknownNode.scala
deleted file mode 100644 (file)
index 1f90a8c..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.util.yaml
-
-/**
- * 
- * @author Christos KK Loverdos <loverdos@gmail.com>.
- */
-case class YAMLUnknownNode(unknownObj: AnyRef, actualType: String) extends YAMLNode {
-  def /(childName: String) = this
-
-  override def isUnknown = false
-
-  def path = ""
-  def withPath(newPath: String) = this
-}
index d7aa4b7..0f22897 100644 (file)
@@ -48,8 +48,8 @@ mongodb.username=aquarium
 # Password for connecting to the persistence service
 mongodb.password=aquarium
 
-# The name of the DB schema to use
-mongodb.dbschema=aquarium
+# The name of the MongoDB database to use
+mongodb.database=aquarium
 
 ### Performance options
 
diff --git a/src/test/scala/gr/grnet/aquarium/computation/TimeslotComputationsTest.scala b/src/test/scala/gr/grnet/aquarium/computation/TimeslotComputationsTest.scala
deleted file mode 100644 (file)
index f550c66..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.computation
-
-import gr.grnet.aquarium.util.TestMethods
-import org.junit.Test
-import java.util.Date
-import junit.framework.Assert._
-import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
-import gr.grnet.aquarium.logic.test.DSLTestBase
-
-/**
- * Tests for the methods that do accounting
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-class TimeslotComputationsTest extends DSLTestBase with TimeslotComputations with TestMethods {
-  @Test
-  def testAlignTimeslots() {
-    var a = List(Timeslot(0, 1))
-    var b = List(Timeslot(0, 2))
-    var result = alignTimeslots(a, b)
-    assertEquals(2, result.size)
-    assertEquals(result.head, Timeslot(0, 1))
-    assertEquals(result.tail.head, Timeslot(1, 2))
-
-    a = List(Timeslot(0, 10))
-    b = List(Timeslot(0, 4), Timeslot(4, 12))
-    result = alignTimeslots(a, b)
-    assertEquals(3, result.size)
-    assertEquals(result.head, Timeslot(0, 4))
-    assertEquals(result.tail.head, Timeslot(4, 10))
-    assertEquals(result.last, Timeslot(10, 12))
-
-    a = List(Timeslot(0, 1), Timeslot(1, 3), Timeslot(3, 4))
-    b = List(Timeslot(0, 2), Timeslot(2, 4))
-    result = alignTimeslots(a, b)
-    assertEquals(4, result.size)
-    assertEquals(result.head, Timeslot(0, 1))
-    assertEquals(result.tail.head, Timeslot(1, 2))
-    assertEquals(result.tail.tail.head, Timeslot(2, 3))
-    assertEquals(result.last, Timeslot(3, 4))
-
-    before
-    val from = new Date(1322555880000L) //Tue, 29 Nov 2011 10:38:00 EET
-    val to = new Date(1322689082000L) //Wed, 30 Nov 2011 23:38:02 EET
-    val agr = dsl.findAgreement("complextimeslots").get
-    a = dslUtils.resolveEffectiveAlgorithmsForTimeslot(Timeslot(from, to), agr).keySet.toList
-    b = dslUtils.resolveEffectivePricelistsForTimeslot(Timeslot(from, to), agr).keySet.toList
-
-    result = alignTimeslots(a, b)
-    assertEquals(9, result.size)
-    assertEquals(result.last, b.last)
-  }
-
-  @Test
-  def testSplitChargeChunks() = {
-    before
-    val from = new Date(1322555880000L) //Tue, 29 Nov 2011 10:38:00 EET
-    val to = new Date(1322689082000L) //Wed, 30 Nov 2011 23:38:02 EET
-
-    val agr = dsl.findAgreement("scaledbandwidth").get
-
-    val alg = dslUtils.resolveEffectiveAlgorithmsForTimeslot(Timeslot(from, to), agr)
-    val price = dslUtils.resolveEffectivePricelistsForTimeslot(Timeslot(from, to), agr)
-    val chunks = splitChargeChunks(alg, price)
-    val algChunks = chunks._1
-    val priceChunks = chunks._2
-
-    assertEquals(algChunks.size, priceChunks.size)
-
-    testSuccessiveTimeslots(algChunks.keySet.toList)
-    testSuccessiveTimeslots(priceChunks.keySet.toList)
-
-    algChunks.keySet.zip(priceChunks.keySet).foreach {
-      t => assertEquals(t._1, t._2)
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala b/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala
deleted file mode 100644 (file)
index 700a170..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.test
-
-import org.junit.Assert._
-import org.junit.{Test}
-import gr.grnet.aquarium.logic.accounting.dsl._
-import gr.grnet.aquarium.util.TestMethods
-
-class DSLTest extends DSLTestBase with TestMethods {
-
-  @Test
-  def testParsePolicies = {
-    before
-    assertEquals(dsl.algorithms.size, 2)
-    assertEquals(dsl.algorithms(0).algorithms.size,
-      dsl.resources.size)
-    assertEquals(dsl.algorithms(1).algorithms.size,
-      dsl.resources.size)
-
-    val d = dsl.findResource("diskspace").get
-    assertNotNone(d)
-
-    assertNotSame(dsl.algorithms(0).algorithms(d),
-      dsl.algorithms(1).algorithms(d))
-  }
-
-  @Test
-  def testParsePricelists = {
-    before
-    assertEquals(3, dsl.pricelists.size)
-    assertNotNone(dsl.findPriceList("everyTue2"))
-    val res = dsl.findResource("diskspace")
-    assertNotNone(res)
-    assertEquals(0.05F,
-      dsl.findPriceList("everyTue2").get.prices.get(res.get).get, 0.01F)
-  }
-
-  @Test
-  def testParseCreditPlans = {
-    before
-    assertEquals(2, dsl.creditplans.size)
-    val plan = dsl.findCreditPlan("every10days")
-    assertNotNone(plan)
-    assertEquals(20, plan.get.credits, 0.1F)
-    assertEquals(4, plan.get.at.size)
-  }
-
-  @Test
-  def testParseResources = {
-    before
-    assertEquals(6, dsl.resources.size)
-    assertNotNone(dsl.findResource("vmtime"))
-    assertTrue(dsl.findResource("vmtime").get.isComplex)
-    //assertEquals("vmid", dsl.findResource("vmtime").get.descriminatorField)
-    assertTrue(!dsl.findResource("diskspace").get.isComplex)
-  }
-
-  @Test
-  def testCronParse = {
-    var input = "12 12 * * *"
-    var output = parseCronString(input)
-    assertEquals(output, List(DSLTimeSpec(12, 12, -1, -1, -1)))
-
-    input = "12 4 3 jaN-ApR *"
-    output = parseCronString(input)
-    assertEquals(4, output.size)
-    assertEquals(output(2), DSLTimeSpec(12, 4, 3, 3, -1))
-
-    input = "12 4 3 jaN-ApR MOn-FRi"
-    output = parseCronString(input)
-    assertEquals(20, output.size)
-
-    input = "12 4 foo jaN-ApR *"
-    assertThrows[DSLParseException](parseCronString(input))
-
-    input = "12 4 * jaN,Mar,ApR 6"
-    output = parseCronString(input)
-    assertEquals(3, output.size)
-    assertEquals(DSLTimeSpec(12, 4, -1, 4, 6), output(2))
-
-    input = "@midnight"
-    assertThrows[DSLParseException](parseCronString(input))
-  }
-
-  @Test
-  def testToYAML: Unit = {
-    before
-
-    assertNotThrows(this.dsl.findAlgorithm("freedisk").get.toYAML)
-    assertNotThrows(this.dsl.findPriceList("everyTue2").get.toYAML)
-    assertNotThrows(this.dsl.findCreditPlan("every10days").get.toYAML)
-
-    val parsed = parse(this.dsl.toYAML)
-    assertEquals(this.dsl.findAlgorithm("freedisk").get, parsed.findAlgorithm("freedisk").get)
-    assertEquals(this.dsl.findPriceList("everyTue2").get, parsed.findPriceList("everyTue2").get)
-    assertEquals(this.dsl.findCreditPlan("every10days").get, parsed.findCreditPlan("every10days").get)
-    //assertEquals(this.dsl.findAgreement("scaledbandwidth").get, parsed.findAgreement("scaledbandwidth").get)
-  }
-}
\ No newline at end of file
diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/DSLTestBase.scala b/src/test/scala/gr/grnet/aquarium/logic/test/DSLTestBase.scala
deleted file mode 100644 (file)
index 41d14f3..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.test
-
-import org.junit.Assert._
-import annotation.tailrec
-import gr.grnet.aquarium.logic.accounting.dsl.{Timeslot, DSL, DSLPolicy}
-
-/**
- * Base class for tests that require access to a DSL description.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-
-class DSLTestBase extends DSL {
-  var dsl: DSLPolicy = _
-
-  def before = {
-    dsl = parse(
-      getClass.getClassLoader.getResourceAsStream("policy.yaml")
-    )
-    assertNotNull(dsl)
-  }
-
-  @tailrec
-  final def testSuccessiveTimeslots(result: List[Timeslot]): Unit = {
-    if (result.isEmpty) return
-    if (result.tail.isEmpty) return
-    if (result.head.to.after(result.tail.head.from))
-      fail("Timeslots not successive: %s %s".format(result.head, result.tail.head))
-    testSuccessiveTimeslots(result.tail)
-  }
-
-  final def testNoGaps(result: List[Timeslot]): Unit =
-    result.reduce {
-      (a,b) =>
-        if(a.to.getTime - b.from.getTime > 1)
-          fail("Timeslots leave gaps: %s %s".format(a.to.getTime, b.from.getTime))
-        a
-    }
-}
\ No newline at end of file
diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/DSLUtilsTest.scala b/src/test/scala/gr/grnet/aquarium/logic/test/DSLUtilsTest.scala
deleted file mode 100644 (file)
index e42425d..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.test
-
-import org.junit.Test
-import org.junit.Assert._
-import gr.grnet.aquarium.util.TestMethods
-import gr.grnet.aquarium.logic.accounting.dsl._
-import annotation.tailrec
-import java.util.{Calendar, Date}
-
-class DSLUtilsTest extends DSLTestBase with DSLUtils with TestMethods {
-
- /* @Test
-  def testFindDays() = {
-    var start = new Date(1321530829000L) // 17/11/2011 13:54:02
-    var end = new Date(1353160515000L)   // 17/11/2012 13:55:15
-
-    var result = findDays(start, end, {
-      c =>
-        c.get(Calendar.DAY_OF_WEEK) == 5}
-    )
-    assertEquals(53, result.size)
-  }
-
-  @Test
-  def testAdjustTime() = {
-    var d = new Date(1321615962000L)        // 18/11/2011 13:32:42
-    var target = new Date(1321573542000L)   // 18/11/2011 01:45:42
-
-    val result = adjustToTime(d, 1, 45)
-    assertEquals(target, result)
-
-    assertThrows(adjustToTime(d, 1, 62))
-  }*/
-
-  @Test
-  def testExpandTimeSpec = {
-    val from =  new Date(1321621969000L) //Fri Nov 18 15:12:49 +0200 2011
-    val to =  new Date(1324214719000L)   //Sun Dec 18 15:25:19 +0200 2011
-
-    var a = DSLTimeSpec(33, 12, -1, -1, 3)
-    var b = DSLTimeSpec(34, 12, -1, -1, 3)
-    var result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    assertEquals(4, result.size)
-
-    a = DSLTimeSpec(33, 12, -1, 10, 3)   // Timespec falling outside from-to
-    b = DSLTimeSpec(34, 12, -1, -1, 3)
-    result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    assertEquals(0, result.size)
-
-    // Would only return an entry if the 1rst of Dec 2011 is Thursday
-    a = DSLTimeSpec(33, 12, 1, -1, 3)
-    b = DSLTimeSpec(34, 12, 1, -1, 3)
-    result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    assertEquals(0, result.size)
-
-    // The 9th of Dec 2011 is Friday
-    //Console.err.println("\n\nBEGIN CALCULATION\t\t" + from + "\t\t" + to +  "\n\n")
-    a = DSLTimeSpec(33, 12, 9, -1, 5)
-    b = DSLTimeSpec(34, 12, 9, -1, 5)
-    result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    //Console.err.println("\n\nEND CALCULATION: " + result +"\n\n")
-    assertEquals(1, result.size)
-
-    // Every day
-    a = DSLTimeSpec(33, 12, -1, -1, -1)
-    b = DSLTimeSpec(34, 12, -1, -1, -1)
-    result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    assertEquals(31, result.size)
-
-    from.setTime(1340614800000L) //  06/25/2012 12:00:00
-    to.setTime(1340982000000L)   // 06/29/2012 18:00:00
-    a = DSLTimeSpec(00, 12, -1, -1, 1 ) // monday at 12:00
-    b = DSLTimeSpec(00, 19, -1, -1, 5) //  friday at 19:00
-    result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    assert(result.size==0)
-
-    from.setTime(1340614800000L) //  06/25/2012 12:00:00
-    to.setTime(1341068400000L)   // 06/30/2012 18:00:00
-    a = DSLTimeSpec(00, 12, -1, -1, 1 ) // monday at 12:00
-    b = DSLTimeSpec(00, 19, -1, -1, 5) //  friday at 19:00
-    result = DSLTimeSpec.expandTimeSpec(a,b,from, to)
-    assert(result.size==1)
-  }
-
-  /*@Test
-  def testExpandTimeSpecs = {
-    val from =  new Date(1321621969000L) //Fri Nov 18 15:12:49 +0200 2011
-    val to =  new Date(1324214719000L)   //Sun Dec 18 15:25:19 +0200 2011
-
-    val a = DSLTimeSpec(33, 12, -1, -1, 3)
-    var result = expandTimeSpecs(List(a), from, to)
-    assertNotEmpty(result)
-    assertEquals(4, result.size)
-
-    val b = DSLTimeSpec(00, 18, -1, -1, -1)
-    result = expandTimeSpecs(List(a,b), from, to)
-    assertNotEmpty(result)
-    assertEquals(34, result.size)
-  }*/
-
-  /*@Test
-  def testEffectiveTimeslots = {
-    val from =  new Date(1321621969000L) //Fri Nov 18 15:12:49 +0200 2011
-    val to =  new Date(1324214719000L)   //Sun Dec 18 15:25:19 +0200 2011
-
-    var repeat = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * *"),
-      parseCronString("00 14 * * *"),
-      "00 12 * * *",
-      "00 14 * * *"
-    )
-
-    var result = effectiveTimeslots(repeat, from,to)
-
-    assertNotEmpty(result)
-    testSuccessiveTimeslots(result)
-    assertEquals(31, result.size)
-
-    //Expansion outside timeframe
-    repeat = DSLTimeFrameRepeat(
-      parseCronString("00 12 * May *"),
-      parseCronString("00 14 * Sep *"),
-      "00 12 * May *",
-      "00 14 * Sep *")
-    result = effectiveTimeslots(repeat, from,to)
-    assertEquals(0, result.size)
-
-    repeat = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * 5"),
-      parseCronString("00 14 * * 1"),
-      "00 12 * * 5",
-      "00 14 * * 1")
-    result = effectiveTimeslots(repeat, from, to)
-    //testSuccessiveTimeslots(result)
-    assertEquals(4, result.size)
-
-    repeat = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * Mon,Wed,Fri"),
-      parseCronString("00 14 * * Tue,Thu,Sat"),
-      "00 12 * * Mon,Wed,Fri",
-      "00 14 * * Tue,Thu,Sat")
-    result = effectiveTimeslots(repeat, from, to)
-    //testSuccessiveTimeslots(result)
-    assertEquals(13, result.size)
-
-    repeat = DSLTimeFrameRepeat(
-      parseCronString("00 00 * May *"),
-      parseCronString("59 23 * Sep *"),
-      "00 00 * May *",
-      "59 23 * Sep *")
-    result = effectiveTimeslots(repeat, new Date(1304121600000L),
-      new Date(1319932800000L))
-    assertNotEmpty(result)
-  } */
-
-  /*@Test
-  def testAllEffectiveTimeslots = {
-    var from = new Date(1321621969000L) //Fri Nov 18 15:12:49 +0200 2011
-    val to =  new Date(1324214719000L)   //Sun Dec 18 15:25:19 +0200 2011
-
-    val repeat1 = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * *"),
-      parseCronString("00 14 * * *"),
-      "00 12 * * *",
-      "00 14 * * *")
-    val repeat2 = DSLTimeFrameRepeat(
-      parseCronString("00 18 * * 5"),
-      parseCronString("00 20 * * 5"),
-      "00 18 * * 5",
-      "00 20 * * 5")
-   // val tf = DSLTimeFrame(from, None, List(repeat1, repeat2),Nil)
-
-    /*var result = allEffectiveTimeslots(tf, Timeslot(from, to))
-    assertEquals(36, result.size)
-    testSuccessiveTimeslots(result)
-
-    result = allEffectiveTimeslots(DSLTimeFrame(new Date(0), None, List(),Nil),
-      Timeslot(new Date(14), new Date(40)))
-    assertEquals(1, result.size)*/
-  } */
-
- /* @Test
-  def testNonEffectiveTimeslots = {
-    val from =  new Date(1321621969000L) //Fri Nov 18 15:12:49 +0200 2011
-    val to =  new Date(1324214719000L)   //Sun Dec 18 15:25:19 +0200 2011
-
-    var repeat = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * *"),
-      parseCronString("00 14 * * *"),
-      "00 12 * * *",
-      "00 14 * * *")
-
-    var result = ineffectiveTimeslots(repeat, from, Some(to))
-    assertEquals(30, result.size)
-    testSuccessiveTimeslots(result)
-    //printTimeslots(result)
-  }*/
-
-  /*@Test
-  def testTimeContinuum : Unit = {
-    val from =  new Date(1321621969000L) //Fri Nov 18 15:12:49 +0200 2011
-    val to =  new Date(1324214719000L)   //Sun Dec 18 15:25:19 +0200 2011
-
-    var repeat = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * *"),
-      parseCronString("00 14 * * *"),
-      "00 12 * * *",
-      "00 14 * * *"
-    )
-
-    val continuum = effectiveTimeslots(repeat, from, Some(to)) ++
-      ineffectiveTimeslots(repeat, from, Some(to)) sortWith sorter
-
-    testSuccessiveTimeslots(continuum)
-    testNoGaps(continuum)
-
-    return
-  } */
-    private def times[R](times:Int,block: => R): R = {
-     val count = times
-     val (ret,s) =  time(block)
-     var sum = s
-     for { i <- 2 to times} {
-       val (_,t) = time(block)
-       sum += t
-       //System.err.println("time" + t +  " count " + count)
-     }
-     //Console.err.println("Elapsed time: " + (sum/count)/1000000L + "\tms")
-     ret
-   }
-
-    private def time[R](block: => R): (R,Long) = {
-     val t0 = System.nanoTime()
-     val result = block    // call-by-name
-     val t1 = System.nanoTime()
-     (result,t1-t0)
-    }
-
-
-  @Test
-  def testFindEffective = {
-    before
-    val agr = dsl.findAgreement("scaledbandwidth").get
-
-    val ts1 = 1322649482000L //Wed, 30 Nov 2011 12:38:02 EET
-    val ts2 = 1322656682000L //Wed, 30 Nov 2011 14:38:02 EET
-    val ts3 = 1322660282000L //Wed, 30 Nov 2011 15:38:02 EET
-    val ts4 = 1322667482000L //Wed, 30 Nov 2011 17:38:02 EET
-    val ts5 = 1322689082000L //Wed, 30 Nov 2011 23:38:02 EET
-    val ts6 = 1322555880000L //Tue, 29 Nov 2011 10:38:00 EET
-
-    var check = new Timeslot(new Date(1322649482000L), new Date(1322654400000L))
-    //Console.err.println("Check " + check)
-    var pricelists = times(1,resolveEffectivePricelistsForTimeslot(Timeslot(new Date(ts1), new Date(ts2)), agr))
-
-    assertEquals(2, pricelists.keySet.size)
-    assertNotNone(pricelists.get(check))
-    assertEquals("foobar", pricelists.head._2.name)
-
-    pricelists = resolveEffectivePricelistsForTimeslot(Timeslot(new Date(ts2), new Date(ts3)), agr)
-    assertEquals(1, pricelists.keySet.size)
-    assertEquals("default", pricelists.head._2.name)
-
-    pricelists = resolveEffectivePricelistsForTimeslot(Timeslot(new Date(ts1), new Date(ts4)), agr)
-    assertEquals(2, pricelists.keySet.size)
-    assertEquals("foobar", pricelists.head._2.name)
-    assertEquals("default", pricelists.tail.head._2.name)
-
-    pricelists = resolveEffectivePricelistsForTimeslot(Timeslot(new Date(ts1), new Date(ts5)), agr)
-    assertEquals(4, pricelists.keySet.size)
-
-    pricelists = times(1,resolveEffectivePricelistsForTimeslot(Timeslot(new Date(ts6), new Date(ts5)), agr))
-    assertEquals(9, pricelists.keySet.size)
-  }
-
-
-  private def printTimeslots(result: List[Timeslot]) = {
-    result.foreach(p => print("from:%s to:%s\n".format(p.from, p.to)))
-  }
-}
\ No newline at end of file
diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/DateUtilsTest.scala b/src/test/scala/gr/grnet/aquarium/logic/test/DateUtilsTest.scala
deleted file mode 100644 (file)
index 33a8823..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.test
-
-import org.junit.Test
-import org.junit.Assert._
-import java.util.{Calendar, Date}
-import gr.grnet.aquarium.util.{TestMethods, DateUtils}
-
-class DateUtilsTest extends DateUtils with TestMethods {
-
-}
\ No newline at end of file
diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/PerfTest.scala b/src/test/scala/gr/grnet/aquarium/logic/test/PerfTest.scala
deleted file mode 100644 (file)
index 9bc9632..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2011-2012 GRNET S.A. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- *   1. Redistributions of source code must retain the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above
- *      copyright notice, this list of conditions and the following
- *      disclaimer in the documentation and/or other materials
- *      provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and
- * documentation are those of the authors and should not be
- * interpreted as representing official policies, either expressed
- * or implied, of GRNET S.A.
- */
-
-package gr.grnet.aquarium.logic.test
-
-import org.junit.Test
-import java.util.{Date}
-import org.junit.Assume._
-import gr.grnet.aquarium.LogicTestsAssumptions
-import gr.grnet.aquarium.logic.accounting.dsl._
-import gr.grnet.aquarium.util.date.TimeHelpers
-
-/**
- * Performance tests for various critical path functions.
- *
- * @author Georgios Gousios <gousiosg@gmail.com>
- */
-class PerfTest extends DSLUtils with DSL {
-
-  @Test
-  def testAllEffectiveTimeslotPerf = {
-    assumeTrue(LogicTestsAssumptions.EnablePerfTests)
-
-    val iter = 1000
-    var start = TimeHelpers.nowMillis()
-    var numResolved = 0
-
-    val from = new Date(0)
-    var to = new Date(2048576095000L) //Fri, 01 Dec 2034 08:54:55 GMT
-    val today = new Date()
-
-    val repeat1 = DSLTimeFrameRepeat(
-      parseCronString("00 12 * * *"),
-      parseCronString("00 14 * * *"),
-      "00 12 * * *",
-      "00 14 * * *")
-    val repeat2 = DSLTimeFrameRepeat(
-      parseCronString("00 18 * * 5"),
-      parseCronString("00 20 * * 5"),
-      "00 18 * * 5",
-      "00 20 * * 5")
-
-    val min = oneYearBack(today, new Date(0)).getTime
-    val max = oneYearAhead(today, new Date(Int.MaxValue * 1000L)).getTime
-
-    (1 to iter).foreach {
-      i => 
-        val rndStart = new Date((min + (scala.math.random * (max - min) + 1)).toLong)
-        var rndEnd = new Date((min + (scala.math.random * (max - min) + 1)).toLong)
-
-        while (rndEnd.before(rndStart)) rndEnd = new Date((min + (scala.math.random * (max - min) + 1)).toLong)
-        val tf = DSLTimeFrame(rndStart, Some(rndEnd), List(repeat1, repeat2))//,Nil)
-
-        numResolved += tf.intervalsOf(Timeslot(new Date(min), new Date(max))).size
-          //allEffectiveTimeslots(tf, Timeslot(new Date(min), new Date(max))).size
-    }
-
-    var total = TimeHelpers.nowMillis() - start
-    print("allEffectiveTimeslots: %d calls in %s msec. (%s resolved)\n".format(iter, total, numResolved))
-  }
-}
\ No newline at end of file
index 098783e..c35f7f7 100644 (file)
@@ -37,17 +37,23 @@ package gr.grnet.aquarium.user
 
 import gr.grnet.aquarium.store.memory.MemStoreProvider
 import gr.grnet.aquarium.logic.accounting.dsl._
-import gr.grnet.aquarium.logic.accounting.Policy
 import gr.grnet.aquarium.util.{Loggable, ContextualLogger}
 import gr.grnet.aquarium.simulation._
 import gr.grnet.aquarium.uid.{UIDGenerator, ConcurrentVMLocalUIDGenerator}
 import org.junit.{Assert, Ignore, Test}
-import gr.grnet.aquarium.logic.accounting.algorithm.{ExecutableCostPolicyAlgorithm, CostPolicyAlgorithmCompiler}
-import gr.grnet.aquarium.{Aquarium, ResourceLocator, AquariumBuilder, AquariumException}
+import gr.grnet.aquarium.logic.accounting.algorithm.{ExecutableChargingBehaviorAlgorithm, CostPolicyAlgorithmCompiler}
+import gr.grnet.aquarium.{Timespan, Aquarium, ResourceLocator, AquariumBuilder, AquariumException}
 import gr.grnet.aquarium.computation.reason.{NoSpecificChangeReason, MonthlyBillingCalculation}
 import gr.grnet.aquarium.util.date.MutableDateCalc
 import gr.grnet.aquarium.computation.BillingMonthInfo
 import gr.grnet.aquarium.computation.state.{UserStateBootstrap, UserState}
+import gr.grnet.aquarium.charging._
+import gr.grnet.aquarium.policy.{PolicyDefinedFullPriceTableRef, StdUserAgreement, EffectiveUnitPrice, EffectivePriceTable, FullPriceTable, ResourceType, StdPolicy, PolicyModel}
+import gr.grnet.aquarium.Timespan
+import scala.Some
+import gr.grnet.aquarium.computation.state.UserStateBootstrap
+import gr.grnet.aquarium.simulation.AquariumSim
+import gr.grnet.aquarium.simulation.ClientSim
 
 
 /**
@@ -57,137 +63,93 @@ import gr.grnet.aquarium.computation.state.{UserStateBootstrap, UserState}
 class UserStateComputationsTest extends Loggable {
   final val DoubleDelta = 0.001
 
-  final val BandwidthPriceUnit = 3.3 //
-  final val VMTimePriceUnit    = 1.5 //
-  final val DiskspacePriceUnit = 2.7 //
-
-  final val OnOffPriceUnit = VMTimePriceUnit
-  final val ContinuousPriceUnit = DiskspacePriceUnit
-  final val DiscretePriceUnit = BandwidthPriceUnit
-
-  final val PolicyYAML = """
-aquariumpolicy:
-  resources:
-    - resource:
-      name: bandwidth
-      unit: MB/Hr
-      complex: false
-      costpolicy: discrete
-    - resource:
-      name: vmtime
-      unit: Hr
-      complex: true
-      costpolicy: onoff
-      descriminatorfield: vmid
-    - resource:
-      name: diskspace
-      unit: MB/hr
-      complex: false
-      costpolicy: continuous
-
-  implicitvars:
-    - price
-    - volume
-
-  algorithms:
-    - algorithm:
-      name: default
-      bandwidth: function bandwidth() {return 1;}
-      vmtime: function vmtime() {return 1;}
-      diskspace: function diskspace() {return 1;}
-      effective:
-        from: 0
-
-  pricelists:
-    - pricelist:
-      name: default
-      bandwidth: %s
-      vmtime: %s
-      diskspace: %s
-      effective:
-        from: 0
-
-  creditplans:
-    - creditplan:
-      name: default
-      credits: 100
-      at: "00 00 1 * *"
-      effective:
-        from: 0
-
-  agreements:
-    - agreement:
-      name: default
-      algorithm: default
-      pricelist: default
-      creditplan: default
-  """.format(
-    BandwidthPriceUnit,
-    VMTimePriceUnit,
-    DiskspacePriceUnit
+  final val BandwidthUnitPrice = 3.3 //
+  final val VMTimeUnitPrice    = 1.5 //
+  final val DiskspaceUnitPrice = 2.7 //
+
+  final val OnOffUnitPrice = VMTimeUnitPrice
+  final val ContinuousUnitPrice = DiskspaceUnitPrice
+  final val DiscreteUnitPrice = BandwidthUnitPrice
+
+  final val DefaultPolicy: PolicyModel = StdPolicy(
+    id = "policy-1",
+    parentID = None,
+    validityTimespan = Timespan(0),
+    resourceTypes = Set(
+      ResourceType("bandwidth", "MB/Hr", DiscreteChargingBehavior),
+      ResourceType("vmtime",    "Hr",    OnOffChargingBehavior),
+      ResourceType("diskspace", "MB/Hr", ContinuousChargingBehavior)
+    ),
+    chargingBehaviorClasses = Set(
+      DiscreteChargingBehavior.getClass.getName,
+      OnOffChargingBehavior.getClass.getName,
+      ContinuousChargingBehavior.getClass.getName
+    ),
+    roleMapping = Map(
+      "default" -> FullPriceTable(Map(
+        "bandwidth" -> EffectivePriceTable(EffectiveUnitPrice(BandwidthUnitPrice, Nil) :: Nil),
+        "vmtime"    -> EffectivePriceTable(EffectiveUnitPrice(VMTimeUnitPrice, Nil) :: Nil),
+        "diskspace" -> EffectivePriceTable(EffectiveUnitPrice(DiskspaceUnitPrice, Nil) :: Nil)
+      ))
+    )
   )
 
   val aquarium = new AquariumBuilder(ResourceLocator.AquariumProperties).
     update(Aquarium.EnvKeys.storeProvider, new MemStoreProvider).
     build()
 
-  Policy.withConfigurator(aquarium) // FIXME
-
   val ResourceEventStore = aquarium.resourceEventStore
 
   val Computations = aquarium.userStateComputations
 
-  val DSL = new DSL {}
-  val DefaultPolicy = DSL parse PolicyYAML
-
-  val DefaultAlgorithm = new ExecutableCostPolicyAlgorithm {
+  val DefaultAlgorithm = new ExecutableChargingBehaviorAlgorithm {
     def creditsForContinuous(timeDelta: Double, oldTotalAmount: Double) =
-      hrs(timeDelta) * oldTotalAmount * ContinuousPriceUnit
+      hrs(timeDelta) * oldTotalAmount * ContinuousUnitPrice
 
     final val creditsForDiskspace = creditsForContinuous(_, _)
     
     def creditsForDiscrete(currentValue: Double) =
-      currentValue * DiscretePriceUnit
+      currentValue * DiscreteUnitPrice
 
     final val creditsForBandwidth = creditsForDiscrete(_)
 
     def creditsForOnOff(timeDelta: Double) =
-      hrs(timeDelta) * OnOffPriceUnit
+      hrs(timeDelta) * OnOffUnitPrice
 
     final val creditsForVMTime = creditsForOnOff(_)
 
     @inline private[this]
     def hrs(millis: Double) = millis / 1000 / 60 / 60
 
-    def apply(vars: Map[DSLCostPolicyVar, Any]): Double = {
-      vars.apply(DSLCostPolicyNameVar) match {
-        case DSLCostPolicyNames.continuous ⇒
-          val unitPrice = vars(DSLUnitPriceVar).asInstanceOf[Double]
-          val oldTotalAmount = vars(DSLOldTotalAmountVar).asInstanceOf[Double]
-          val timeDelta = vars(DSLTimeDeltaVar).asInstanceOf[Double]
+    def apply(vars: Map[ChargingInput, Any]): Double = {
+      vars.apply(ChargingBehaviorNameInput) match {
+        case ChargingBehaviorNames.continuous ⇒
+          val unitPrice = vars(UnitPriceInput).asInstanceOf[Double]
+          val oldTotalAmount = vars(OldTotalAmountInput).asInstanceOf[Double]
+          val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double]
 
-          Assert.assertEquals(ContinuousPriceUnit, unitPrice, DoubleDelta)
+          Assert.assertEquals(ContinuousUnitPrice, unitPrice, DoubleDelta)
 
           creditsForContinuous(timeDelta, oldTotalAmount)
 
-        case DSLCostPolicyNames.discrete ⇒
-          val unitPrice = vars(DSLUnitPriceVar).asInstanceOf[Double]
-          val currentValue = vars(DSLCurrentValueVar).asInstanceOf[Double]
+        case ChargingBehaviorNames.discrete ⇒
+          val unitPrice = vars(UnitPriceInput).asInstanceOf[Double]
+          val currentValue = vars(CurrentValueInput).asInstanceOf[Double]
 
-          Assert.assertEquals(DiscretePriceUnit, unitPrice, DoubleDelta)
+          Assert.assertEquals(DiscreteUnitPrice, unitPrice, DoubleDelta)
 
           creditsForDiscrete(currentValue)
 
-        case DSLCostPolicyNames.onoff ⇒
-          val unitPrice = vars(DSLUnitPriceVar).asInstanceOf[Double]
-          val timeDelta = vars(DSLTimeDeltaVar).asInstanceOf[Double]
+        case ChargingBehaviorNames.onoff ⇒
+          val unitPrice = vars(UnitPriceInput).asInstanceOf[Double]
+          val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double]
 
-          Assert.assertEquals(OnOffPriceUnit, unitPrice, DoubleDelta)
+          Assert.assertEquals(OnOffUnitPrice, unitPrice, DoubleDelta)
 
           creditsForOnOff(timeDelta)
 
-        case DSLCostPolicyNames.once ⇒
-          val currentValue = vars(DSLCurrentValueVar).asInstanceOf[Double]
+        case ChargingBehaviorNames.once ⇒
+          val currentValue = vars(CurrentValueInput).asInstanceOf[Double]
           currentValue
 
         case name ⇒
@@ -197,20 +159,20 @@ aquariumpolicy:
 
     override def toString = "DefaultAlgorithm(%s)".format(
       Map(
-        DSLCostPolicyNames.continuous -> "hrs(timeDelta) * oldTotalAmount * %s".format(ContinuousPriceUnit),
-        DSLCostPolicyNames.discrete   -> "currentValue * %s".format(DiscretePriceUnit),
-        DSLCostPolicyNames.onoff      -> "hrs(timeDelta) * %s".format(OnOffPriceUnit),
-        DSLCostPolicyNames.once       -> "currentValue"))
+        ChargingBehaviorNames.continuous -> "hrs(timeDelta) * oldTotalAmount * %s".format(ContinuousUnitPrice),
+        ChargingBehaviorNames.discrete   -> "currentValue * %s".format(DiscreteUnitPrice),
+        ChargingBehaviorNames.onoff      -> "hrs(timeDelta) * %s".format(OnOffUnitPrice),
+        ChargingBehaviorNames.once       -> "currentValue"))
   }
 
   val DefaultCompiler  = new CostPolicyAlgorithmCompiler {
-    def compile(definition: String): ExecutableCostPolicyAlgorithm = {
+    def compile(definition: String): ExecutableChargingBehaviorAlgorithm = {
       DefaultAlgorithm
     }
   }
   //val DefaultAlgorithm = justForSure(DefaultCompiler.compile("")).get // hardcoded since we know exactly what this is
 
-  val VMTimeDSLResource = DefaultPolicy.findResource("vmtime").get
+  val VMTimeDSLResource = DefaultPolicy.resourceTypesMap("vmtime")
 
   // For this to work, the definitions must match those in the YAML above.
   // Those StdXXXResourceSim are just for debugging convenience anyway, so they must match by design.
@@ -238,11 +200,11 @@ aquariumpolicy:
   val policyOccurredMillis  = policyDateCalc.toMillis
   val policyValidFromMillis = policyDateCalc.copy.goPreviousYear.toMillis
   val policyValidToMillis   = policyDateCalc.copy.goNextYear.toMillis
-  aquarium.policyStore.storePolicyEntry(DefaultPolicy.toPolicyEntry(policyOccurredMillis, policyValidFromMillis,
-    policyValidToMillis))
+
+  aquarium.policyStore.insertPolicy(DefaultPolicy)
 
   val AquariumSim_ = AquariumSim(List(VMTimeResourceSim, DiskspaceResourceSim, BandwidthResourceSim), aquarium.resourceEventStore)
-  val DefaultResourcesMap = AquariumSim_.resourcesMap
+  val DefaultResourcesMap = DefaultPolicy.resourceTypesMap//AquariumSim_.resourcesMap
 
   val UserCKKL  = AquariumSim_.newUser("CKKL", UserCreationDate)
 
@@ -257,8 +219,7 @@ aquariumpolicy:
   val UserStateBootstrapper = UserStateBootstrap(
     userID = UserCKKL.userID,
     userCreationMillis = UserCreationDate.getTime(),
-    initialRole = "default",
-    initialAgreement = DSLAgreement.DefaultAgreementName,
+    initialAgreement = StdUserAgreement("", None, Timespan(0), "default", PolicyDefinedFullPriceTableRef),
     initialCredits = 0.0
   )
 
@@ -468,7 +429,7 @@ aquariumpolicy:
 
     // Policy: from 2012-01-01 to Infinity
 
-    clog.debugMap("DefaultResourcesMap", DefaultResourcesMap.map, 1)
+    clog.debugMap("DefaultResourcesMap", DefaultResourcesMap, 1)
 
     val userState = doFullMonthlyBilling(clog, BillingMonthInfoJan, BillingMonthInfoJan.monthStopMillis)