--- /dev/null
+language: scala
+scala:
+ - 2.9.1
+ - 2.9.2
+jdk:
+ - openjdk6
+ - openjdk7
+ - oraclejdk7
\ No newline at end of file
# 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
--- /dev/null
+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
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}
/**
*
}
- 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 = {
def eventsStoreFolder = apply(EnvKeys.eventsStoreFolder)
- def algorithmCompiler = apply(EnvKeys.algorithmCompiler)
-
def eventBus = apply(EnvKeys.eventBus)
def userStateComputations = apply(EnvKeys.userStateComputations)
def converters = apply(EnvKeys.converters)
-// def actorProvider = apply(EnvKeys.actorProvider)
-
def saveResourceEventsToEventsStoreFolder = apply(EnvKeys.eventsStoreSaveRCEvents)
def saveIMEventsToEventsStoreFolder = apply(EnvKeys.eventsStoreSaveIMEvents)
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")
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")
newInstance(envKey.keyType, classOf[SimpleTimerService].getName)
}
- checkNoPropsOverride(EnvKeys.algorithmCompiler) { _ ⇒ SimpleCostPolicyAlgorithmCompiler }
-
checkNoPropsOverride(EnvKeys.userStateComputations) { envKey ⇒
newInstance(envKey.keyType, classOf[UserStateComputations].getName)
}
--- /dev/null
+/*
+ * 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
+
+import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
+
+/**
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+
+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)
+}
val userStateBootstrap = UserStateBootstrap(
this._userID,
userCreationMillis,
- initialRole,
- aquarium.initialAgreementForRole(initialRole, userCreationMillis),
+ aquarium.initialUserAgreementForRole(initialRole, userCreationMillis),
aquarium.initialBalanceForRole(initialRole, userCreationMillis)
)
BillingMonthInfo.fromMillis(now),
now,
userStateBootstrap,
- aquarium.currentResourcesMap,
+ aquarium.currentResourceTypesMap,
InitialUserActorSetup(),
stdUserStateStoreFunc,
None
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,
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)
}
/**
* (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
* 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
* 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.
*
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)
) {
/**
* 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 = {
}
/**
- * 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
* 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)
) {
/**
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))
override def isBillableEvent(event: ResourceEventModel) = {
// ON events do not contribute, only OFF ones.
- OnOffCostPolicyValues.isOFFValue(event.value)
+ OnOffChargingBehaviorValues.isOFFValue(event.value)
}
/**
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)
}
}
}
-object OnOffCostPolicyValues {
+object OnOffChargingBehaviorValues {
final val ON = 1.0
final val OFF = 0.0
}
/**
- * 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.
*
* 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 = {
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.util.yaml
+package gr.grnet.aquarium.charging
/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
+ *
+ * @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
+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")
+
+
+
+
--- /dev/null
+/*
+ * 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.charging
+
+import gr.grnet.aquarium.AquariumException
+
+/**
+ * Encapsulates the possible states that a resource with an
+ * [[gr.grnet.aquarium.charging.OnOffChargingBehavior]]
+ * can be.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+sealed abstract class OnOffPolicyResourceState(val state: String) {
+ def isOn: Boolean = !isOff
+ def isOff: Boolean = !isOn
+}
+
+object OnResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.on) {
+ override def isOn = true
+}
+
+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.logic.test
+package gr.grnet.aquarium.charging
-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 {
+/**
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
-}
\ No newline at end of file
+object OnOffPolicyResourceStateNames {
+ final val on = "on"
+ final val off = "off"
+}
case class Chargeslot(
startMillis: Long,
stopMillis: Long,
- algorithmDefinition: String,
unitPrice: Double,
computedCredits: Option[Double] = None) {
new MutableDateCalc(startMillis).toYYYYMMDDHHMMSSSSS,
new MutableDateCalc(stopMillis).toYYYYMMDDHHMMSSSSS,
unitPrice,
- computedCredits,
- algorithmDefinition
+ computedCredits
)
}
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.
* @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
}
*
*/
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.
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
}
oldCredits: Double,
oldTotalAmount: Double,
newTotalAmount: Double,
- dslResource: DSLResource,
- defaultResourceMap: DSLResourcesMap,
- agreementNamesByTimeslot: SortedMap[Timeslot, String],
- algorithmCompiler: CostPolicyAlgorithmCompiler,
+ resourceType: ResourceType,
+ agreementByTimeslot: SortedMap[Timeslot, UserAgreementModel],
policyStore: PolicyStore,
clogOpt: Option[ContextualLogger] = None
): (Timeslot, List[Chargeslot]) = {
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, policyByTimeslot, 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 policyByTimeslot = policyStore.loadAndSortPoliciesWithin(referenceTimeslot.from.getTime, referenceTimeslot.to.getTime)
- (referenceTimeslot, relevantPolicies, previousResourceEvent.value)
+ (referenceTimeslot, policyByTimeslot, 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
+ // TODO: Check semantics of this
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 {
+ val policyByTimeslot = relevantPolicyOpt match {
case Some(relevantPolicy) ⇒
- Map(referenceTimeslot -> relevantPolicy)
+ SortedMap(referenceTimeslot -> relevantPolicy)
case None ⇒
throw new AquariumInternalError("No relevant policy found for %s".format(referenceTimeslot))
}
- (referenceTimeslot, relevantPolicies, previousValue)
+ (referenceTimeslot, policyByTimeslot, previousValue)
}
val initialChargeslots = computeInitialChargeslots(
referenceTimeslot,
- dslResource,
- relevantPolicies,
- agreementNamesByTimeslot,
+ resourceType,
+ policyByTimeslot,
+ 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,
clog.debugMap("valueMap", valueMap, 1)
// This is it
- val credits = execAlgorithm.apply(valueMap)
+ val credits = SimpleExecutableChargingBehaviorAlgorithm.apply(valueMap)
chargeslot.copyWithCredits(credits)
}
}
/**
- * 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.
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
/**
*
*/
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
def findUserStateAtEndOfBillingMonth(
userStateBootstrap: UserStateBootstrap,
billingMonthInfo: BillingMonthInfo,
- defaultResourcesMap: DSLResourcesMap,
+ defaultResourceTypesMap: Map[String, ResourceType],
calculationReason: UserStateChangeReason,
storeFunc: UserState ⇒ UserState,
clogOpt: Option[ContextualLogger] = None
val userState0 = doFullMonthBilling(
userStateBootstrap,
billingMonthInfo,
- defaultResourcesMap,
+ defaultResourceTypesMap,
calculationReason,
storeFunc,
Some(clog)
val theValue = currentResourceEvent.value
val theDetails = currentResourceEvent.details
- val resourcesMap = userStateWorker.resourcesMap
+ val resourceTypesMap = userStateWorker.resourceTypesMap
val currentResourceEventDebugInfo = rcDebugInfo(currentResourceEvent)
clog.begin(currentResourceEventDebugInfo)
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)
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.
val actualFirstEvent = currentResourceEvent
- if(costPolicy.isBillableFirstEvent(actualFirstEvent) &&
- costPolicy.mustGenerateDummyFirstEvent) {
+ if(chargingBehavior.isBillableFirstEvent(actualFirstEvent) &&
+ chargingBehavior.mustGenerateDummyFirstEvent) {
clog.debug("First event of its kind %s", currentResourceEventDebugInfo)
// 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))
}
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 agreementByTimeslot = _workingUserState.agreementHistory.agreementsByTimeslot
// clog.debug("Computing full chargeslots")
val (referenceTimeslot, fullChargeslots) = timeslotComputations.computeFullChargeslots(
oldCredits,
oldAmount,
newAccumulatingAmount,
- dslResource,
- resourcesMap,
- alltimeAgreements,
- algorithmCompiler,
+ resourceType,
+ agreementByTimeslot,
policyStore,
Some(clog)
)
else
List(currentResourceEvent),
fullChargeslots,
- dslResource,
+ resourceType,
currentResourceEvent.isSynthetic
)
clog.debug("%s = %s", shortClassNameOf(newWalletEntry), newWalletEntry)
def doFullMonthBilling(
userStateBootstrap: UserStateBootstrap,
billingMonthInfo: BillingMonthInfo,
- defaultResourcesMap: DSLResourcesMap,
+ defaultResourceTypesMap: Map[String, ResourceType],
calculationReason: UserStateChangeReason,
storeFunc: UserState ⇒ UserState,
clogOpt: Option[ContextualLogger] = None
billingMonthInfo,
billingMonthInfo.monthStopMillis,
userStateBootstrap,
- defaultResourcesMap,
+ defaultResourceTypesMap,
calculationReason,
storeFunc,
clogOpt
*/
billingEndTimeMillis: Long,
userStateBootstrap: UserStateBootstrap,
- defaultResourcesMap: DSLResourcesMap,
+ defaultResourceTypesMap: Map[String, ResourceType],
calculationReason: UserStateChangeReason,
storeFunc: UserState ⇒ UserState,
clogOpt: Option[ContextualLogger] = None
val previousBillingMonthUserState = findUserStateAtEndOfBillingMonth(
userStateBootstrap,
previousBillingMonthInfo,
- defaultResourcesMap,
+ defaultResourceTypesMap,
calculationReason,
storeFunc,
clogSome
// 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)
LatestResourceEventsWorker.fromList(specialEvents),
ImplicitlyIssuedResourceEventsWorker.Empty,
IgnoredFirstResourceEventsWorker.Empty,
- userStateWorker.resourcesMap
+ userStateWorker.resourceTypesMap
)
_workingUserState = processResourceEvents(
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.
//
// def userCreationFormatedDate = new MutableDateCalc(userCreationMillis).toString
- def findDSLAgreementForTime(at: Long): Option[DSLAgreement] = {
+ def findDSLAgreementForTime(at: Long): Option[UserAgreementModel] = {
agreementHistory.findForTime(at)
}
userCreationMillis: Long,
occurredMillis: Long,
totalCredits: Double,
- initialRole: String,
- initialAgreement: String,
+ initialAgreement: UserAgreementModel,
calculationReason: UserStateChangeReason = InitialUserStateSetup(None)
) = {
LatestResourceEventsSnapshot.Empty,
0L,
totalCredits,
- RoleHistory.initial(initialRole, userCreationMillis),
- AgreementHistory.initial(initialAgreement, userCreationMillis),
+ RoleHistory.initial(initialAgreement.role, userCreationMillis),
+ AgreementHistory.initial(initialAgreement),
OwnedResourcesSnapshot.Empty,
Nil,
occurredMillis,
usb.userCreationMillis,
occurredMillis,
usb.initialCredits,
- usb.initialRole,
usb.initialAgreement,
calculationReason
)
package gr.grnet.aquarium.computation.state
+import gr.grnet.aquarium.policy.UserAgreementModel
+
/**
* This is used to bootstrap the [[gr.grnet.aquarium.computation.state.UserState]].
*
case class UserStateBootstrap(
userID: String,
userCreationMillis: Long,
- initialRole: String,
- initialAgreement: String,
+ initialAgreement: UserAgreementModel,
initialCredits: Double
)
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.
* The resource events that were first (and unused) of their kind.
*/
ignoredFirstResourceEvents: IgnoredFirstResourceEventsWorker,
- resourcesMap: DSLResourcesMap
+ resourceTypesMap: Map[String, ResourceType]
) {
/**
* 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(
/**
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)
}
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
)
}
}
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.
* @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)
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)
}
}
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`.
billingMonth: Int,
resourceEvents: List[ResourceEventModel], // current is at the head
chargeslots: List[Chargeslot],
- resourceDef: DSLResource,
+ resourceDef: ResourceType,
isSynthetic: Boolean) {
def currentResourceEvent = resourceEvents.head
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
* @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)
* @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
}
}
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 ⇒
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"))
}
+++ /dev/null
-/*
- * 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)
+++ /dev/null
-/*
- * 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"
-}
+++ /dev/null
-/*
- * 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)
-}
+++ /dev/null
-/*
- * 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)
-}
* @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!!!
+++ /dev/null
-/*
- * 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"
- }
-}
+++ /dev/null
-/*
- * 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)
-}
+++ /dev/null
-/*
- * 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)
- }
-}
+++ /dev/null
-/*
- * 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*/
*/
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
- }
}
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.
to: Option[Date],
repeat: List[DSLTimeFrameRepeat] /*,
cronRepeat: List[DSLCronSpec]*/
-) extends DSLItem {
+) {
to match {
case Some(x) =>
* */
def intervalsOf(t:Timeslot) : List[Timeslot]=
if(repeat.isEmpty)
- t.overlappingTimeslots(List(Timeslot(start,end)))
+ List(t) // .overlappingTimeslots(List(Timeslot(start,end)))
else {
val result = new mutable.ListBuffer[Timeslot]()
var offset = t.from
}
}
- 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(
* @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
+++ /dev/null
-/*
- * 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
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.
* @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)
+ def resolveEffectiveUnitPricesForTimeslot(
+ alignedTimeslot: 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))
+ }
- /*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)
+ case AdHocFullPriceTableRef(fullPriceTable) ⇒
+ fullPriceTable
+ }
+
+ val effectivePriceTable = fullPriceTable.perResource.get(resourceType.name) match {
+ case None ⇒
+ throw new AquariumInternalError("Unknown resource type %s".format(role))
+
+ case Some(effectivePriceTable) ⇒
+ effectivePriceTable
}
+
+ resolveEffective(alignedTimeslot, effectivePriceTable)
}
- 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")
- } */
+ /*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)
+ }
+ }
+
+ 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")
+ } */
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
- }
+ immutable.SortedMap[Timeslot, T] = {
+ //Console.err.println("\n\nInput timeslot: " + timeslot0 + "\n\n")
+ ///printPolicy(policy)
+ val ret = resolveEffective3(timeslot0,policy) //HERE
+ //printMap(ret)
+ ret
+ }
- def resolveEffective3[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
- immutable.SortedMap[Timeslot, T] = {
- assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
- val timeslot = timeslot0 //TODO: timeslot0.align(5000)
+
+ def resolveEffective3(
+ alignedTimeslot: Timeslot,
+ effectivePriceTable: EffectivePriceTable
+ ): immutable.SortedMap[Timeslot, Double/*unit price*/] = {
+// assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
+ val timeslot = alignedTimeslot //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
(subtimeslots_of_this_policy))
*
* @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)
+++ /dev/null
-/*
- * 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"
-}
* or implied, of GRNET S.A.
*/
-package gr.grnet.aquarium.util.yaml
+package gr.grnet.aquarium.policy
/**
+ * A specific price table for a particular resource type that has information of what unit price is
+ * effective when.
*
- * @author Georgios Gousios <gousiosg@gmail.com>.
+ * NOTE: head of `priceOverrides` is most specific.
+ *
+ * @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
- def withPath(newPath: String) = this.copy(path = newPath)
-}
+case class EffectivePriceTable(priceOverrides: List[EffectiveUnitPrice])
* or implied, of GRNET S.A.
*/
-package gr.grnet.aquarium.store
+package gr.grnet.aquarium.policy
-import gr.grnet.aquarium.AquariumException
+import gr.grnet.aquarium.logic.accounting.dsl.DSLTimeFrame
/**
- * 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
+
+case class EffectiveUnitPrice(unitPrice: Double, when: DSLTimeFrame) // TODO: use DSLTimeframe
* or implied, of GRNET S.A.
*/
-package gr.grnet.aquarium.util.yaml
-
-import collection.mutable
+package gr.grnet.aquarium.policy
/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
+ * A full price table provides detailed pricing information for all resources.
+ *
+ * @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
+case class FullPriceTable(perResource: Map[String/*Resource*/, EffectivePriceTable]) {
+ def effectivePriceTableForResourceType(resourceType: String): Option[EffectivePriceTable] = {
+ perResource.get(resourceType)
+ }
- def withPath(newPath: String) = this.copy(path = newPath)
+ def effectivePriceTableForResourceType(resourceType: ResourceType): Option[EffectivePriceTable] = {
+ perResource.get(resourceType.name)
+ }
}
* or implied, of GRNET S.A.
*/
-package gr.grnet.aquarium.computation
-package state
-package parts
-
-import gr.grnet.aquarium.util.date.MutableDateCalc
-import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
+package gr.grnet.aquarium.policy
/**
- * 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`.
+ * A reference to a full price table. This either relates ("by reference") to a known full price table
+ * or is an ad-hoc full price table.
*
* @author Christos KK Loverdos <loverdos@gmail.com>
*/
-case class AgreementHistoryItem(name: String, validFrom: Long, validTo: Long = Long.MaxValue) {
- require(validTo > validFrom)
- require(!name.isEmpty)
- def timeslot = Timeslot(validFrom, validTo)
+sealed trait FullPriceTableRef {
+ def isAdHoc: Boolean
+}
+
+/**
+ * Refers to an existing full price table that belongs to the given role. The role is implied from the user agreement
+ * that contains this instance and must be used to retrieve the exact full price table from the Aquarium policy.
+ */
+case object PolicyDefinedFullPriceTableRef extends FullPriceTableRef {
+ def isAdHoc: Boolean = false
+}
- override def toString =
- "AgreementHistoryItem(%s, %s, %s)".
- format(name, new MutableDateCalc(validFrom), new MutableDateCalc(validTo))
+case class AdHocFullPriceTableRef(adhocPriceTable: FullPriceTable) extends FullPriceTableRef {
+ def isAdHoc: Boolean = true
}
--- /dev/null
+/*
+ * 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
+
+/**
+ * The algorithm used for charging a resource instance.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+
+case class PolicyChargingAlgorithm(definition: String, language: String = "javascript") {
+}
--- /dev/null
+/*
+ * 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
+
+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.
+ * Policies change over the course of time. The underlying representation must be immutable.
+ *
+ * TODO: The following sentence will self-destruct at most after 200 commits.
+ * This model supersedes the original DSLPolicy, after changes in requirements and some thoughts on simplicity.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+
+trait PolicyModel extends JsonSupport {
+ def id: String
+
+ def parentID: Option[String]
+
+ def idInStore: Option[Any]
+
+
+ /**
+ * The time period within which this policy is valid.
+ */
+ def validityTimespan: Timespan
+
+ final def validFrom: Long = validityTimespan.fromMillis
+
+ final def validTo: Long = validityTimespan.toMillis
+
+ /**
+ * All known resource types for the policy's validity period.
+ */
+ def resourceTypes: Set[ResourceType]
+
+ /**
+ * All known charging behaviors for the policy's validity period.<p/>
+ *
+ * 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 chargingBehaviorClasses: Set[String/*ImplementationClassName*/]
+
+ /**
+ * Each role is mapped to a full price table.
+ */
+ def roleMapping: Map[String/*Role*/, FullPriceTable]
+
+
+ /**
+ * All the known roles for the policy's validity period.
+ * These names must be common between all communicating parties, i.e. the IM component that sends
+ * [[gr.grnet.aquarium.event.model.im.IMEventModel]] events.
+ *
+ * This is a derived set, from the keys of `roleMapping`
+ */
+ 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
+}
* or implied, of GRNET S.A.
*/
-package gr.grnet.aquarium.util.yaml
+package gr.grnet.aquarium.policy
+
+import gr.grnet.aquarium.Timespan
/**
- *
- * @author Christos KK Loverdos <loverdos@gmail.com>.
+ *
+ * @param validityPeriod The period when this price table is valid.
+ * @param prices A map from resource to its unit price.
*/
-case class YAMLUnknownNode(unknownObj: AnyRef, actualType: String) extends YAMLNode {
- def /(childName: String) = this
-
- override def isUnknown = false
-
- def path = ""
- def withPath(newPath: String) = this
+case class PolicyUnitPrices(validityPeriod: Timespan, prices: Map[String, Double]) {
}
--- /dev/null
+/*
+ * 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
+
+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 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, chargingBehavior: ChargingBehavior)
--- /dev/null
+/*
+ * 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
+
+import gr.grnet.aquarium.Timespan
+
+/**
+ * Standard implementation of Aquarium policy model.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+
+case class StdPolicy(
+ id: String,
+ parentID: Option[String],
+ validityTimespan: Timespan,
+ resourceTypes: Set[ResourceType],
+ chargingBehaviorClasses: Set[String],
+ roleMapping: Map[String/*Role*/, FullPriceTable]
+) extends PolicyModel {
+
+ 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
/**
- * A boolean node
*
- * @author Georgios Gousios <gousiosg@gmail.com>
+ * @author Christos KK Loverdos <loverdos@gmail.com>
*/
-case class YAMLBooleanNode(path: String, bool: Boolean) extends YAMLNode {
- def /(childName: String) = YAMLEmptyNode
-
- override def booleanValue = bool
-
- override def isBoolean = false
+case class StdUserAgreement(
+ id: String,
+ parentID: Option[String],
+ validityTimespan: Timespan,
+ role: String,
+ fullPriceTableRef: FullPriceTableRef
+) extends UserAgreementModel {
- def withPath(newPath: String) = this.copy(path = newPath)
-}
\ No newline at end of file
+ def idInStore: Option[Any] = None
+}
* 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
/**
*
- * @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))
- }
+trait UserAgreementModel {
+ def id: String
+
+ def idInStore: Option[Any]
+
+ def parentID: Option[String]
+
+ def validityTimespan: Timespan
+
+ def role: String
+
+ def fullPriceTableRef: FullPriceTableRef
+
+ def timeslot = validityTimespan.toTimeslot
+
+ def validFrom = validityTimespan.fromMillis
- def toYAML: String = YAMLHelpers.dumpYAML(toMap)
-}
\ No newline at end of file
+ def validTo = validityTimespan.toMillis
+}
--- /dev/null
+/*
+ * 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
+
+/**
+ * Includes all the definitions for the aquarium policy-related entities.
+ */
+package object policy {}
+++ /dev/null
-/*
- * 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
package gr.grnet.aquarium.simulation
-import gr.grnet.aquarium.logic.accounting.dsl.DSLResourcesMap
import gr.grnet.aquarium.store.ResourceEventStore
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)
}
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
/**
* @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)
}
*/
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}
/**
* @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)
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
+ )
}
}
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.
* @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)
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)
}
}
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.
* @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
)
(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
newResourceEvent(
occurredTime,
receivedTime,
- OnOffCostPolicyValues.OFF,
+ OnOffChargingBehaviorValues.OFF,
details,
eventVersion
)
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}
/**
* @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)
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
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
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.
* @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]()
Tags.UserStateTag -> _userStates.size,
Tags.ResourceEventTag -> _resourceEvents.size,
Tags.IMEventTag -> imEventById.size,
- "PolicyEntry" -> _policyEntries.size
+ "PolicyEntry" -> _policies.size
)
"MemStoreProvider(%s)" format map
}
//- 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
}
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.
* @author Georgios Gousios <gousiosg@gmail.com>
*/
class MongoDBStore(
+ val aquarium: Aquarium,
val mongo: Mongo,
val database: String,
val username: String,
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)
//+ UserStateStore
def insertUserState(userState: UserState) = {
- MongoDBStore.insertUserState(
+ MongoDBStore.insertObject(
userState.copy(_id = new ObjectId().toString),
userStates,
MongoDBStore.jsonSupportToDBObject
//+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
}
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))
}
}
- def dbObjectToPolicyEntry(dbObj: DBObject): PolicyEntry = {
- PolicyEntry.fromJson(JSON.serialize(dbObj))
- }
-
def ping(mongo: Mongo): Unit = synchronized {
// This requires a network roundtrip
mongo.isLocked
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,
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)
}
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)
}
}
* @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(PrefixAndDot + "threads.allowed.to.block.for.connection.multiplier")
}
}
\ No newline at end of file
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
- }
-}
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
+++ /dev/null
-/*
- * 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)
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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)
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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)
- }
- }
-}
-
-
-
-
+++ /dev/null
-/*
- * 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)
-}
# 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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
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
/**
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 ⇒
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.
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)
val UserStateBootstrapper = UserStateBootstrap(
userID = UserCKKL.userID,
userCreationMillis = UserCreationDate.getTime(),
- initialRole = "default",
- initialAgreement = DSLAgreement.DefaultAgreementName,
+ initialAgreement = StdUserAgreement("", None, Timespan(0), "default", PolicyDefinedFullPriceTableRef),
initialCredits = 0.0
)
// 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)