From ecceede87168f8bd3391a74b18eab2eb6c59aaa5 Mon Sep 17 00:00:00 2001 From: Christos KK Loverdos Date: Tue, 14 Feb 2012 15:43:42 +0200 Subject: [PATCH] Small (semantic) change towards a new charging algorithm Does not compile --- .../aquarium/logic/accounting/Accounting.scala | 100 ++++++++++++-------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/Accounting.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/Accounting.scala index 8372321..3a34c5d 100644 --- a/src/main/scala/gr/grnet/aquarium/logic/accounting/Accounting.scala +++ b/src/main/scala/gr/grnet/aquarium/logic/accounting/Accounting.scala @@ -63,32 +63,42 @@ trait Accounting extends DSLUtils with Loggable { val instanceId = currentResourceEvent.instanceId val currentValue = currentResourceEvent.value val currentOccurredMillis = currentResourceEvent.occurredMillis + val currentResourceEventDebugStr = currentResourceEvent.toDebugString(defaultResourcesMap, false) + + + def validateCostPolicy(toCheck: DSLCostPolicy, whatEvent: String) { + if(costPolicy != toCheck) { + throw new Exception("Actual cost policy %s is not the same as provided %s for %s event %s". + format(costPolicy, toCheck, whatEvent, currentResourceEventDebugStr)) + } + } + def validateCostPolicyM(toCheckM: Maybe[DSLCostPolicy], whatEvent: String): Unit = { + toCheckM match { + case Just(toCheck) ⇒ + validateCostPolicy(toCheck, whatEvent) + + case _ ⇒ + throw new Exception("Could not verify cost policy %s for %s event %s". + format(costPolicy, whatEvent, currentResourceEventDebugStr)) + } + } ///////////////////////////////////////////////////////////////////// // Validations ///////////////////////////////////////////////////////////////////// - // 1. Validate cost policy - val actualCostPolicyM = currentResourceEvent.findCostPolicyM(defaultResourcesMap) - val currentResourceEventDebugStr = currentResourceEvent.toDebugString(defaultResourcesMap, false) - actualCostPolicyM match { - case Just(actualCostPolicy) ⇒ - if(costPolicy != actualCostPolicy) { - throw new Exception("Actual cost policy %s is not the same as provided %s for event %s". - format(actualCostPolicy, costPolicy, currentResourceEventDebugStr)) - } - case _ ⇒ - throw new Exception("Could not verify cost policy %s for event %s". - format(costPolicy, currentResourceEventDebugStr)) - } + // 1. Validate cost policy for current event + val currentEventCostPolicyM = currentResourceEvent.findCostPolicyM(defaultResourcesMap) + validateCostPolicyM(currentEventCostPolicyM, "current") // 2. Validate previous resource event previousResourceEventM match { + // We have a previous event case Just(previousResourceEvent) ⇒ if(!costPolicy.needsPreviousEventForCreditAndAmountCalculation) { throw new Exception("Provided previous event but cost policy %s does not need one".format(costPolicy)) } - // 3. resource and instanceId + // 3. Validate resource and instanceId for previous resource event val previousResource = previousResourceEvent.resource val previousInstanceId = previousResourceEvent.instanceId (resource == previousResource, instanceId == previousInstanceId) match { @@ -107,21 +117,27 @@ trait Accounting extends DSLUtils with Loggable { format((resource, instanceId), (previousResource, previousInstanceId))) } + // 4. Validate cost policy for previous resource event + val previousEventCostPolicyM = previousResourceEvent.findCostPolicyM(defaultResourcesMap) + validateCostPolicyM(previousEventCostPolicyM, "previous") + + // We do not have a previous event case NoVal ⇒ if(costPolicy.needsPreviousEventForCreditAndAmountCalculation) { - throw new Exception("Did not provid previous event but cost policy %s needa one".format(costPolicy)) + throw new Exception("Did not provide previous event but cost policy %s needs one".format(costPolicy)) } + // We cannot obtain a previous resource event case failed @ Failed(e, m) ⇒ throw new Exception("Error obtaining previous event".format(m), e) } - // 4. Make sure this is billable. - // It is the caller's responsibility to provide us with billable events + // 5. Make the current event is billable. + // It is the caller's responsibility to provide us with billable events costPolicy.isBillableEventBasedOnValue(currentValue) match { case true ⇒ case false ⇒ - throw new Exception("Event not billable %s".format(currentResourceEventDebugStr)) + throw new Exception("Not billable event %s".format(currentResourceEventDebugStr)) } ///////////////////////////////////////////////////////////////////// @@ -131,10 +147,10 @@ trait Accounting extends DSLUtils with Loggable { previousAccumulatingAmountM.getOr(0.0), currentOccurredMillis - previousResourceEventM.map(_.occurredMillis).getOr(currentOccurredMillis), previousResourceEventM.map(_.value).getOr(0.0), - currentValue) + currentValue, + 1.0 /*UNITPRICE*/) // Now, we need to find the proper agreement(s) and feed the data to them. - Nil } @@ -218,26 +234,26 @@ trait Accounting extends DSLUtils with Loggable { * Creates a list of wallet entries by applying the agreement provisions on * the resource state. * - * @param resourceEvent The resource event to create charges for + * @param currentResourceEvent The resource event to create charges for * @param agreement The agreement applicable to the user mentioned in the event - * @param currentValue The current state of the resource - * @param currentSnapshotDate The last time the resource state was updated + * @param previousAmount The current state of the resource + * @param previousOccurred The last time the resource state was updated */ - def chargeEvent(resourceEvent: ResourceEvent, - agreement: DSLAgreement, - currentValue: Double, - currentSnapshotDate: Date, + def chargeEvent(currentResourceEvent: ResourceEvent, + agreements: List[String], + previousAmount: Double, + previousOccurred: Date, related: List[WalletEntry]): Maybe[List[WalletEntry]] = { - assert(currentSnapshotDate.getTime <= resourceEvent.occurredMillis) + assert(previousOccurred.getTime <= currentResourceEvent.occurredMillis) - if (!resourceEvent.validate()) + if (!currentResourceEvent.validate()) return Failed(new AccountingException("Event not valid")) val policy = Policy.policy - val dslResource = policy.findResource(resourceEvent.resource) match { + val dslResource = policy.findResource(currentResourceEvent.resource) match { case Some(x) => x - case None => return Failed(new AccountingException("No resource [%s]".format(resourceEvent.resource))) + case None => return Failed(new AccountingException("No resource [%s]".format(currentResourceEvent.resource))) } /* This is a safeguard against the special case where the last @@ -246,14 +262,14 @@ trait Accounting extends DSLUtils with Loggable { * this is the first time the resource state has been recorded. * Charging in this case only makes sense for discrete resources. */ - if (currentSnapshotDate.getTime == resourceEvent.occurredMillis) { + if (previousOccurred.getTime == currentResourceEvent.occurredMillis) { dslResource.costPolicy match { case DiscreteCostPolicy => //Ok case _ => return Some(List()) } } - val creditCalculationValueM = dslResource.costPolicy.getValueForCreditCalculation(Just(currentValue), resourceEvent.value) + val creditCalculationValueM = dslResource.costPolicy.getValueForCreditCalculation(Just(previousAmount), currentResourceEvent.value) val amount = creditCalculationValueM match { case failed @ Failed(_, _) ⇒ return failed @@ -267,7 +283,7 @@ trait Accounting extends DSLUtils with Loggable { // above, since this point won't be reached in case of error. val isFinal = dslResource.costPolicy match { case OnOffCostPolicy => - OnOffPolicyResourceState(currentValue) match { + OnOffPolicyResourceState(previousAmount) match { case OnResourceState => false case OffResourceState => true } @@ -275,29 +291,29 @@ trait Accounting extends DSLUtils with Loggable { } val timeslot = dslResource.costPolicy match { - case DiscreteCostPolicy => Timeslot(new Date(resourceEvent.occurredMillis), - new Date(resourceEvent.occurredMillis + 1)) - case _ => Timeslot(currentSnapshotDate, new Date(resourceEvent.occurredMillis)) + case DiscreteCostPolicy => Timeslot(new Date(currentResourceEvent.occurredMillis), + new Date(currentResourceEvent.occurredMillis + 1)) + case _ => Timeslot(previousOccurred, new Date(currentResourceEvent.occurredMillis)) } val chargeChunks = calcChangeChunks(agreement, amount, dslResource, timeslot) val timeReceived = System.currentTimeMillis - val rel = related.map{x => x.sourceEventIDs}.flatten ++ List(resourceEvent.id) + val rel = related.map{x => x.sourceEventIDs}.flatten ++ List(currentResourceEvent.id) val entries = chargeChunks.map { c => WalletEntry( id = CryptoUtils.sha1(c.id), - occurredMillis = resourceEvent.occurredMillis, + occurredMillis = currentResourceEvent.occurredMillis, receivedMillis = timeReceived, sourceEventIDs = rel, value = c.cost, reason = c.reason, - userId = resourceEvent.userId, - resource = resourceEvent.resource, - instanceId = resourceEvent.instanceId, + userId = currentResourceEvent.userId, + resource = currentResourceEvent.resource, + instanceId = currentResourceEvent.instanceId, finalized = isFinal ) } -- 1.7.10.4