WIP: ResourceEvent-related refactorings
[aquarium] / src / main / scala / gr / grnet / aquarium / logic / accounting / Accounting.scala
index 38d0e6b..b376bff 100644 (file)
@@ -38,13 +38,15 @@ package gr.grnet.aquarium.logic.accounting
 import gr.grnet.aquarium.util.shortClassNameOf
 import algorithm.CostPolicyAlgorithmCompiler
 import dsl._
-import gr.grnet.aquarium.logic.events.{WalletEntry, ResourceEvent}
 import collection.immutable.SortedMap
 import java.util.Date
 import com.ckkloverdos.maybe.{NoVal, Maybe, Failed, Just}
-import gr.grnet.aquarium.util.date.MutableDateCalc
 import gr.grnet.aquarium.util.{ContextualLogger, CryptoUtils, Loggable}
 import gr.grnet.aquarium.store.PolicyStore
+import gr.grnet.aquarium.event.{WalletEntry}
+import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
+import gr.grnet.aquarium.event.resource.ResourceEventModel
+import gr.grnet.aquarium.{AquariumInternalError, AquariumException}
 
 /**
  * A timeslot together with the algorithm and unit price that apply for this particular timeslot.
@@ -117,9 +119,10 @@ trait Accounting extends DSLUtils with Loggable {
   protected
   def resolveEffectiveAlgorithmsAndPriceLists(alignedTimeslot: Timeslot,
                                               agreement: DSLAgreement,
-                                              clogM: Maybe[ContextualLogger] = NoVal): (Map[Timeslot, DSLAlgorithm], Map[Timeslot, DSLPriceList]) = {
+                                              clogOpt: Option[ContextualLogger] = None):
+          (Map[Timeslot, DSLAlgorithm], Map[Timeslot, DSLPriceList]) = {
 
-    val clog = ContextualLogger.fromOther(clogM, logger, "resolveEffectiveAlgorithmsAndPriceLists()")
+    val clog = ContextualLogger.fromOther(clogOpt, logger, "resolveEffectiveAlgorithmsAndPriceLists()")
 
     // Note that most of the code is taken from calcChangeChunks()
     val alg = resolveEffectiveAlgorithmsForTimeslot(alignedTimeslot, agreement)
@@ -138,9 +141,9 @@ trait Accounting extends DSLUtils with Loggable {
                                 dslResource: DSLResource,
                                 policiesByTimeslot: Map[Timeslot, DSLPolicy],
                                 agreementNamesByTimeslot: Map[Timeslot, String],
-                                contextualLogger: Maybe[ContextualLogger] = NoVal): Maybe[List[Chargeslot]] = Maybe {
+                                clogOpt: Option[ContextualLogger] = None): List[Chargeslot] = {
 
-    val clog = ContextualLogger.fromOther(contextualLogger, logger, "computeInitialChargeslots()")
+    val clog = ContextualLogger.fromOther(clogOpt, logger, "computeInitialChargeslots()")
 //    clog.begin()
 
     val policyTimeslots = policiesByTimeslot.keySet
@@ -183,13 +186,13 @@ trait Accounting extends DSLUtils with Loggable {
         case None ⇒
           val errMsg = "Unknown agreement %s during %s".format(agreementName, alignedTimeslot)
           clog.error("%s", errMsg)
-          throw new Exception(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, Just(clog))
+          val r = resolveEffectiveAlgorithmsAndPriceLists(alignedTimeslot, agreement, Some(clog))
           val algorithmByTimeslot: Map[Timeslot, DSLAlgorithm] = r._1
           val pricelistByTimeslot: Map[Timeslot, DSLPriceList] = r._2
 
@@ -215,15 +218,15 @@ trait Accounting extends DSLUtils with Loggable {
 
             val chargeslot = (algorithmDefOpt, priceUnitOpt) match {
               case (None, None) ⇒
-                throw new Exception(
+                throw new AquariumException(
                   "Unknown algorithm and price unit for resource %s during %s".
                     format(dslResource, finegrainedTimeslot))
               case (None, _) ⇒
-                throw new Exception(
+                throw new AquariumException(
                   "Unknown algorithm for resource %s during %s".
                     format(dslResource, finegrainedTimeslot))
               case (_, None) ⇒
-                throw new Exception(
+                throw new AquariumException(
                   "Unknown price unit for resource %s during %s".
                     format(dslResource, finegrainedTimeslot))
               case (Some(algorithmDefinition), Some(priceUnit)) ⇒
@@ -251,8 +254,8 @@ trait Accounting extends DSLUtils with Loggable {
    * Compute the charge slots generated by a particular resource event.
    *
    */
-  def computeFullChargeslots(previousResourceEventM: Maybe[ResourceEvent],
-                             currentResourceEvent: ResourceEvent,
+  def computeFullChargeslots(previousResourceEventOpt: Option[ResourceEventModel],
+                             currentResourceEvent: ResourceEventModel,
                              oldCredits: Double,
                              oldTotalAmount: Double,
                              newTotalAmount: Double,
@@ -261,9 +264,9 @@ trait Accounting extends DSLUtils with Loggable {
                              agreementNamesByTimeslot: Map[Timeslot, String],
                              algorithmCompiler: CostPolicyAlgorithmCompiler,
                              policyStore: PolicyStore,
-                             contextualLogger: Maybe[ContextualLogger] = NoVal): Maybe[(Timeslot, List[Chargeslot])] = Maybe {
+                             clogOpt: Option[ContextualLogger] = None): (Timeslot, List[Chargeslot]) = {
 
-    val clog = ContextualLogger.fromOther(contextualLogger, logger, "computeFullChargeslots()")
+    val clog = ContextualLogger.fromOther(clogOpt, logger, "computeFullChargeslots()")
 //    clog.begin()
 
     val occurredDate = currentResourceEvent.occurredDate
@@ -274,9 +277,9 @@ trait Accounting extends DSLUtils with Loggable {
     val (referenceTimeslot, relevantPolicies, previousValue) = costPolicy.needsPreviousEventForCreditAndAmountCalculation match {
       // We need a previous event
       case true ⇒
-        previousResourceEventM match {
+        previousResourceEventOpt match {
           // We have a previous event
-          case Just(previousResourceEvent) ⇒
+          case Some(previousResourceEvent) ⇒
 //            clog.debug("Have previous event")
 //            clog.debug("previousValue = %s", previousResourceEvent.value)
 
@@ -291,16 +294,10 @@ trait Accounting extends DSLUtils with Loggable {
             (referenceTimeslot, relevantPolicies, previousResourceEvent.value)
 
           // We do not have a previous event
-          case NoVal ⇒
-            throw new Exception(
+          case None ⇒
+            throw new AquariumException(
               "Unable to charge. No previous event given for %s".
                 format(currentResourceEvent.toDebugString()))
-
-          // We could not obtain a previous event
-          case failed @ Failed(e, m) ⇒
-            throw new Exception(
-              "Unable to charge. Could not obtain previous event for %s".
-                format(currentResourceEvent.toDebugString()), e)
         }
 
       // We do not need a previous event
@@ -315,84 +312,50 @@ trait Accounting extends DSLUtils with Loggable {
 //        clog.debug("referenceTimeslot = %s".format(referenceTimeslot))
 
 //        clog.debug("Calling policyStore.loadValidPolicyEntryAt(%s)", new MutableDateCalc(occurredMillis))
-        val relevantPolicyM = policyStore.loadValidPolicyAt(occurredMillis, dsl)
+        val relevantPolicyOpt = policyStore.loadValidPolicyAt(occurredMillis, dsl)
 //        clog.debug("  ==> relevantPolicyM = %s", relevantPolicyM)
 
-        val relevantPolicies = relevantPolicyM match {
-          case Just(relevantPolicy) ⇒
+        val relevantPolicies = relevantPolicyOpt match {
+          case Some(relevantPolicy) ⇒
             Map(referenceTimeslot -> relevantPolicy)
-          case NoVal ⇒
-            throw new Exception("No relevant policy found for %s".format(referenceTimeslot))
-          case failed @ Failed(e, _) ⇒
-            throw new Exception("No relevant policy found for %s".format(referenceTimeslot), e)
 
+          case None ⇒
+            throw new AquariumInternalError("No relevant policy found for %s".format(referenceTimeslot))
         }
 
         (referenceTimeslot, relevantPolicies, previousValue)
     }
 
-    val initialChargeslotsM = computeInitialChargeslots(
+    val initialChargeslots = computeInitialChargeslots(
       referenceTimeslot,
       dslResource,
       relevantPolicies,
       agreementNamesByTimeslot,
-      Just(clog)
+      Some(clog)
     )
 
-    val fullChargeslotsM = initialChargeslotsM.map { chargeslots ⇒
-      chargeslots.map {
-        case chargeslot @ Chargeslot(startMillis, stopMillis, algorithmDefinition, unitPrice, _) ⇒
-          val execAlgorithmM = algorithmCompiler.compile(algorithmDefinition)
-          execAlgorithmM match {
-            case NoVal ⇒
-              throw new Exception("Could not compile algorithm %s".format(algorithmDefinition))
-
-            case failed @ Failed(e, m) ⇒
-              throw new Exception(m, e)
-
-            case Just(execAlgorithm) ⇒
-              val valueMap = costPolicy.makeValueMap(
-                oldCredits,
-                oldTotalAmount,
-                newTotalAmount,
-                stopMillis - startMillis,
-                previousValue,
-                currentResourceEvent.value,
-                unitPrice
-              )
+    val fullChargeslots = initialChargeslots.map {
+      case chargeslot @ Chargeslot(startMillis, stopMillis, algorithmDefinition, unitPrice, _) ⇒
+        val execAlgorithm = algorithmCompiler.compile(algorithmDefinition)
+        val valueMap = costPolicy.makeValueMap(
+          oldCredits,
+          oldTotalAmount,
+          newTotalAmount,
+          stopMillis - startMillis,
+          previousValue,
+          currentResourceEvent.value,
+          unitPrice
+        )
 
 //              clog.debug("execAlgorithm = %s", execAlgorithm)
-              clog.debugMap("valueMap", valueMap, 1)
-
-              // This is it
-              val creditsM = execAlgorithm.apply(valueMap)
+        clog.debugMap("valueMap", valueMap, 1)
 
-              creditsM match {
-                case NoVal ⇒
-                  throw new Exception(
-                    "Could not compute credits for resource %s during %s".
-                      format(dslResource.name, Timeslot(new Date(startMillis), new Date(stopMillis))))
-
-                case failed @ Failed(e, m) ⇒
-                  throw new Exception(m, e)
-
-                case Just(credits) ⇒
-                  chargeslot.copy(computedCredits = Some(credits))
-              }
-          }
-      }
+        // This is it
+        val credits = execAlgorithm.apply(valueMap)
+        chargeslot.copy(computedCredits = Some(credits))
     }
 
-    val result = fullChargeslotsM match {
-      case Just(fullChargeslots) ⇒
-        referenceTimeslot -> fullChargeslots
-      case NoVal ⇒
-        null
-      case failed @ Failed(e, m) ⇒
-        throw new Exception(m, e)
-    }
-
-//    clog.end()
+    val result = referenceTimeslot -> fullChargeslots
 
     result
   }
@@ -406,7 +369,7 @@ trait Accounting extends DSLUtils with Loggable {
    * @param previousAmount The current state of the resource
    * @param previousOccurred The last time the resource state was updated
    */
-  def chargeEvent(currentResourceEvent: ResourceEvent,
+  def chargeEvent(currentResourceEvent: ResourceEventModel,
                   agreements: SortedMap[Timeslot, String],
                   previousAmount: Double,
                   previousOccurred: Date,
@@ -463,7 +426,7 @@ trait Accounting extends DSLUtils with Loggable {
           Some(x)
         ) match {
           case Just(x) => x
-          case Failed(f, e) => return Failed(f,e)
+          case Failed(f) => return Failed(f)
           case NoVal => List()
         }
         entries
@@ -486,7 +449,7 @@ trait Accounting extends DSLUtils with Loggable {
    *                  resource event boundaries
    * @return A list of wallet entries, one for each
    */
-  def chargeEvent(event: ResourceEvent,
+  def chargeEvent(event: ResourceEventModel,
                   agr: DSLAgreement,
                   previousAmount: Double,
                   previousOccurred: Date,
@@ -498,8 +461,8 @@ trait Accounting extends DSLUtils with Loggable {
     chargeFor.map{x => assert(true,
       Timeslot(previousOccurred, new Date(event.occurredMillis)))}
 
-    if (!event.validate())
-      return Failed(new AccountingException("Event not valid"))
+//    if (!event.validate())
+//      return Failed(new AccountingException("Event not valid"))
 
     val policy = Policy.policy
     val dslResource = policy.findResource(event.resource) match {
@@ -523,7 +486,7 @@ trait Accounting extends DSLUtils with Loggable {
 
     val creditCalculationValueM = dslResource.costPolicy.getValueForCreditCalculation(Just(previousAmount), event.value)
     val amount = creditCalculationValueM match {
-      case failed @ Failed(_, _) ⇒
+      case failed @ Failed(_) ⇒
         return failed
       case Just(amount) ⇒
         amount
@@ -566,7 +529,7 @@ trait Accounting extends DSLUtils with Loggable {
      */
     val chargeChunks = calcChangeChunks(agr, amount, dslResource, timeslot)
 
-    val timeReceived = System.currentTimeMillis
+    val timeReceived = TimeHelpers.nowMillis()
 
     val rel = event.id :: related.map{x => x.sourceEventIDs}.flatten
 
@@ -578,9 +541,9 @@ trait Accounting extends DSLUtils with Loggable {
           sourceEventIDs = rel,
           value = c.cost,
           reason = c.reason,
-          userId = event.userId,
+          userId = event.userID,
           resource = event.resource,
-          instanceId = event.instanceId,
+          instanceId = event.instanceID,
           finalized = isFinal
         )
     }
@@ -751,8 +714,8 @@ case class ChargeChunk(value: Double, algorithm: String,
 
   def id(): String =
     CryptoUtils.sha1("%f%s%f%s%s%d".format(value, algorithm, price, when.toString,
-      resource.name, System.currentTimeMillis()))
+      resource.name, TimeHelpers.nowMillis()))
 }
 
 /** An exception raised when something goes wrong with accounting */
-class AccountingException(msg: String) extends Exception(msg)
+class AccountingException(msg: String) extends AquariumException(msg)