package gr.grnet.aquarium.charging
-import gr.grnet.aquarium.event.model.resource.ResourceEventModel
-import gr.grnet.aquarium.AquariumException
+import gr.grnet.aquarium.Aquarium
+import gr.grnet.aquarium.charging.state.UserAgreementHistoryModel
+import gr.grnet.aquarium.computation.BillingMonthInfo
+import gr.grnet.aquarium.event.{CreditsModel, DetailsModel}
+import gr.grnet.aquarium.message.avro.gen.{UserStateMsg, WalletEntryMsg, ResourcesChargingStateMsg, ResourceTypeMsg, ResourceInstanceChargingStateMsg, ResourceEventMsg}
+import gr.grnet.aquarium.message.MessageConstants
/**
* A charging behavior for which resource events just carry a credit amount that will be added to the total one.
*
* @author Christos KK Loverdos <loverdos@gmail.com>
*/
-final class OnceChargingBehavior
- extends ChargingBehavior(
- ChargingBehaviorAliases.once,
- Set(ChargingBehaviorNameInput, CurrentValueInput)) {
+final class OnceChargingBehavior extends ChargingBehaviorSkeleton(Nil) {
+ def computeCreditsToSubtract(
+ resourceInstanceChargingState: ResourceInstanceChargingStateMsg,
+ oldCredits: CreditsModel.Type,
+ timeDeltaMillis: Long,
+ unitPrice: CreditsModel.Type
+ ): (CreditsModel.Type, String /* explanation */) = {
- /**
- * This is called when we have the very first event for a particular resource instance, and we want to know
- * if it is billable or not.
- */
- def isBillableFirstEvent(event: ResourceEventModel) = {
- true
- }
+ val currentValue = CreditsModel.from(resourceInstanceChargingState.getCurrentValue)
+ // Always remember to multiply with the `unitPrice`, since it scales the credits, depending on
+ // the particular resource type tha applies.
+ val credits = CreditsModel.mul(currentValue, unitPrice)
+ val explanation = "Value(%s) * UnitPrice(%s)".format(currentValue, unitPrice)
- def mustGenerateDummyFirstEvent = false // no need to
+ (credits, explanation)
+ }
- def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]) = {
- oldAmount
+ def computeSelectorPath(
+ chargingBehaviorDetails: DetailsModel.Type,
+ resourceInstanceChargingState: ResourceInstanceChargingStateMsg,
+ currentResourceEvent: ResourceEventMsg,
+ referenceFromMillis: Long,
+ referenceToMillis: Long,
+ totalCredits: CreditsModel.Type
+ ): List[String] = {
+ List(MessageConstants.DefaultSelectorKey)
}
- def getResourceInstanceInitialAmount = 0.0
+ override def processResourceEvent(
+ aquarium: Aquarium,
+ resourceEvent: ResourceEventMsg,
+ resourceType: ResourceTypeMsg,
+ billingMonthInfo: BillingMonthInfo,
+ resourcesChargingState: ResourcesChargingStateMsg,
+ userAgreementHistoryModel: UserAgreementHistoryModel,
+ userStateMsg: UserStateMsg,
+ walletEntryRecorder: WalletEntryMsg ⇒ Unit
+ ): (Int, Double) = {
+ // The credits are given in the value
+ // But we cannot just apply them, since we also need to take into account the unit price.
+ // Normally, the unit price is 1.0 but we have the flexibility to allow more stuff).
- def supportsImplicitEvents = false
+ // 1. Ensure proper initial state per resource and per instance
+ ensureInitializedWorkingState(resourcesChargingState,resourceEvent)
- def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = false
+ // 2. Fill in data from the new event
+ val stateOfResourceInstance = resourcesChargingState.getStateOfResourceInstance
+ val resourcesChargingStateDetails = resourcesChargingState.getDetails
+ val instanceID = resourceEvent.getInstanceID
+ val resourceInstanceChargingState = stateOfResourceInstance.get(instanceID)
+ fillWorkingResourceInstanceChargingStateFromEvent(resourceInstanceChargingState, resourceEvent)
- def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, occurredMillis: Long) = {
- throw new AquariumException("constructImplicitEndEventFor() Not compliant with %s".format(this))
+ computeWalletEntriesForNewEvent(
+ resourceEvent,
+ resourceType,
+ billingMonthInfo,
+ userStateMsg.getTotalCredits,
+ resourceEvent.getOccurredMillis,
+ resourceEvent.getOccurredMillis + 1, // single point in time
+ userAgreementHistoryModel.agreementByTimeslot,
+ resourcesChargingStateDetails,
+ resourceInstanceChargingState,
+ aquarium,
+ walletEntryRecorder
+ )
+ }
+
+ def initialChargingDetails = {
+ DetailsModel.make
+ }
+
+ def computeNewAccumulatingAmount(
+ resourceInstanceChargingState: ResourceInstanceChargingStateMsg,
+ eventDetails: DetailsModel.Type
+ ): CreditsModel.Type = {
+ CreditsModel.from(resourceInstanceChargingState.getOldAccumulatingAmount)
}
-}
-object OnceChargingBehavior {
- private[this] final val TheOne = new OnceChargingBehavior
+ def createVirtualEventsForRealtimeComputation(
+ userID: String,
+ resourceTypeName: String,
+ resourceInstanceID: String,
+ eventOccurredMillis: Long,
+ resourceInstanceChargingState: ResourceInstanceChargingStateMsg
+ ): List[ResourceEventMsg] = {
- def apply(): OnceChargingBehavior = TheOne
+ // We optimize and generate no virtual event
+ Nil
+ }
}