From b7b59f6f530833efcedb0f4a08327e7fd8957992 Mon Sep 17 00:00:00 2001 From: Christos KK Loverdos Date: Fri, 13 Jul 2012 12:16:56 +0300 Subject: [PATCH] Manually revert to ddd366d --- src/main/resources/aquarium.properties | 12 +- src/main/resources/policy.json | 61 +++++ src/main/resources/policy.scala | 45 ++-- src/main/scala/gr/grnet/aquarium/Aquarium.scala | 66 +++-- .../scala/gr/grnet/aquarium/AquariumBuilder.scala | 42 +--- src/main/scala/gr/grnet/aquarium/Main.scala | 1 + .../scala/gr/grnet/aquarium/ResourceLocator.scala | 21 +- .../grnet/aquarium/charging/ChargingBehavior.scala | 261 +------------------- ...orNames.scala => ChargingBehaviorAliases.scala} | 2 +- .../charging/ContinuousChargingBehavior.scala | 101 ++++++++ .../charging/DiscreteChargingBehavior.scala | 93 +++++++ .../aquarium/charging/OnOffChargingBehavior.scala | 136 ++++++++++ ...mes.scala => OnOffChargingBehaviorValues.scala} | 10 +- .../charging/OnOffPolicyResourceState.scala | 17 +- .../aquarium/charging/OnceChargingBehavior.scala | 82 ++++++ .../computation/TimeslotComputations.scala | 5 +- .../computation/UserStateComputations.scala | 5 +- .../computation/state/UserStateWorker.scala | 4 +- ...impleExecutableChargingBehaviorAlgorithm.scala} | 20 +- .../aquarium/logic/accounting/dsl/Timeslot.scala | 3 - .../grnet/aquarium/policy/EffectiveUnitPrice.scala | 5 +- .../gr/grnet/aquarium/policy/PolicyHistory.scala | 70 ++++++ .../gr/grnet/aquarium/policy/PolicyModel.scala | 15 +- .../gr/grnet/aquarium/policy/ResourceType.scala | 6 +- .../scala/gr/grnet/aquarium/policy/StdPolicy.scala | 2 +- .../gr/grnet/aquarium/service/AkkaService.scala | 2 +- .../aquarium/service/FinagleRESTService.scala | 6 +- .../gr/grnet/aquarium/service/RESTPaths.scala | 2 +- .../aquarium/service/StoreWatcherService.scala | 2 + .../gr/grnet/aquarium/simulation/ResourceSim.scala | 4 +- .../simulation/StdBandwidthResourceSim.scala | 4 +- .../simulation/StdDiskspaceResourceSim.scala | 2 +- .../aquarium/simulation/StdVMTimeResourceSim.scala | 2 +- .../aquarium/store/memory/MemStoreProvider.scala | 2 +- .../aquarium/store/mongodb/MongoDBPolicy.scala | 7 +- src/main/scala/gr/grnet/aquarium/util/Lock.scala | 53 ++++ src/test/resources/aquarium.properties | 12 +- src/test/resources/policy.json | 61 +++++ .../aquarium/logic/test/DSLTimeFrameTest.scala | 1 - .../grnet/aquarium/logic/test/TimeslotTest.scala | 3 +- .../gr/grnet/aquarium/policy/StdPolicyTest.scala | 85 +++++++ .../policy/test/EffectiveUnitPriceTest.scala | 156 ------------ .../aquarium/user/UserStateComputationsTest.scala | 39 ++- 43 files changed, 919 insertions(+), 609 deletions(-) create mode 100644 src/main/resources/policy.json rename src/main/scala/gr/grnet/aquarium/charging/{ChargingBehaviorNames.scala => ChargingBehaviorAliases.scala} (98%) create mode 100644 src/main/scala/gr/grnet/aquarium/charging/ContinuousChargingBehavior.scala create mode 100644 src/main/scala/gr/grnet/aquarium/charging/DiscreteChargingBehavior.scala create mode 100644 src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehavior.scala rename src/main/scala/gr/grnet/aquarium/charging/{OnOffPolicyResourceStateNames.scala => OnOffChargingBehaviorValues.scala} (90%) create mode 100644 src/main/scala/gr/grnet/aquarium/charging/OnceChargingBehavior.scala rename src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/{SimpleExecutableChargingBehaviorAlgorithm$.scala => SimpleExecutableChargingBehaviorAlgorithm.scala} (82%) create mode 100644 src/main/scala/gr/grnet/aquarium/policy/PolicyHistory.scala create mode 100644 src/main/scala/gr/grnet/aquarium/util/Lock.scala create mode 100644 src/test/resources/policy.json create mode 100644 src/test/scala/gr/grnet/aquarium/policy/StdPolicyTest.scala delete mode 100644 src/test/scala/gr/grnet/aquarium/policy/test/EffectiveUnitPriceTest.scala diff --git a/src/main/resources/aquarium.properties b/src/main/resources/aquarium.properties index dfaadec..325d4a9 100644 --- a/src/main/resources/aquarium.properties +++ b/src/main/resources/aquarium.properties @@ -74,20 +74,14 @@ anystore.reconnect.period.millis=1000 # DO NOT TOUCH the following options, unless you know what you are doing ####### -# Actor subsystem -actor.provider.class=gr.grnet.aquarium.service.SimpleLocalRoleableActorProviderService # Class that initializes the REST service rest.service.class=gr.grnet.aquarium.service.FinagleRESTService rest.shutdown.timeout.millis=2000 # Store subsystem store.provider.class=gr.grnet.aquarium.store.mongodb.MongoDBStoreProvider -# Override the user store (if present, it will not be given by the store provider above) -#user.state.store.class=gr.grnet.aquarium.store.memory.MemStorede the event store (if present, it will not be given by the store provider above) -#resource.event.store.class= -# Override the user event store (if present, it will not be given by the store provider above) -#user.event.store.class= -# Override the user event store (if present, it will not be given by the store provider above) -#policy.store.class= + +# A time period in milliseconds for which we can tolerate stale parts regarding user state. +user.state.timestamp.threshold=1 # Administrative REST API authorization cookie admin.cookie=1 \ No newline at end of file diff --git a/src/main/resources/policy.json b/src/main/resources/policy.json new file mode 100644 index 0000000..179e153 --- /dev/null +++ b/src/main/resources/policy.json @@ -0,0 +1,61 @@ +{ + "id":"750E6309-AB60-41B4-8D4B-9FFEA6EF843C", + + "validityTimespan":{ + "fromMillis":0, + "toMillis":9223372036854775807 + }, + + "resourceTypes":[ + { + "name":"bandwidth", + "unit":"MB/Hr", + "chargingBehavior":"gr.grnet.aquarium.charging.DiscreteChargingBehavior" + }, + { + "name":"vmtime", + "unit":"Hr", + "chargingBehavior":"gr.grnet.aquarium.charging.OnOffChargingBehavior" + }, + { + "name":"diskspace", + "unit":"MB/Hr", + "chargingBehavior":"gr.grnet.aquarium.charging.ContinuousChargingBehavior" + } + ], + + "chargingBehaviors":[ + "gr.grnet.aquarium.charging.DiscreteChargingBehavior", + "gr.grnet.aquarium.charging.OnOffChargingBehavior", + "gr.grnet.aquarium.charging.ContinuousChargingBehavior", + "gr.grnet.aquarium.charging.OnceChargingBehavior" + ], + + "roleMapping":{ + "default":{ + "perResource":{ + "bandwidth":{ + "priceOverrides":[ + { + "unitPrice":0.01 + } + ] + }, + "vmtime":{ + "priceOverrides":[ + { + "unitPrice":0.01 + } + ] + }, + "diskspace":{ + "priceOverrides":[ + { + "unitPrice":0.01 + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/policy.scala b/src/main/resources/policy.scala index 68176fc..0657131 100644 --- a/src/main/resources/policy.scala +++ b/src/main/resources/policy.scala @@ -3,32 +3,31 @@ import gr.grnet.aquarium.policy.{EffectiveUnitPrice, EffectivePriceTable, FullPr 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, + id = "750E6309-AB60-41B4-8D4B-9FFEA6EF843C", + parentID = None, - validityTimespan = Timespan(0), + validityTimespan = Timespan(0), - resourceTypes = Set( - ResourceType("bandwidth", "MB/Hr", DiscreteChargingBehavior), - ResourceType("vmtime", "Hr", OnOffChargingBehavior), - ResourceType("diskspace", "MB/Hr", ContinuousChargingBehavior) - ), + resourceTypes = Set( + ResourceType("bandwidth", "MB/Hr", classOf[DiscreteChargingBehavior].getName), + ResourceType("vmtime", "Hr", classOf[OnOffChargingBehavior].getName), + ResourceType("diskspace", "MB/Hr", classOf[ContinuousChargingBehavior].getName) + ), - chargingBehaviorClasses = Set( - DiscreteChargingBehavior.getClass.getName, - OnOffChargingBehavior.getClass.getName, - ContinuousChargingBehavior.getClass.getName, - OnceChargingBehavior.getClass.getName - ), + chargingBehaviors = Set( + classOf[DiscreteChargingBehavior].getName, + classOf[OnOffChargingBehavior].getName, + classOf[ContinuousChargingBehavior].getName, + classOf[OnceChargingBehavior].getName + ), - roleMapping = Map( - "default" -> FullPriceTable(Map( - "bandwidth" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil), - "vmtime" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil), - "diskspace" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil) - )) - ) - ) \ No newline at end of file + roleMapping = Map( + "default" -> FullPriceTable(Map( + "bandwidth" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil), + "vmtime" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil), + "diskspace" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil) + )) + ) +) \ No newline at end of file diff --git a/src/main/scala/gr/grnet/aquarium/Aquarium.scala b/src/main/scala/gr/grnet/aquarium/Aquarium.scala index a31281e..a71c08e 100644 --- a/src/main/scala/gr/grnet/aquarium/Aquarium.scala +++ b/src/main/scala/gr/grnet/aquarium/Aquarium.scala @@ -38,7 +38,7 @@ package gr.grnet.aquarium import com.ckkloverdos.env.Env import com.ckkloverdos.key.{IntKey, StringKey, LongKey, TypedKeySkeleton, TypedKey, BooleanKey} import com.ckkloverdos.props.Props -import gr.grnet.aquarium.store.{PolicyStore, UserStateStore, IMEventStore, ResourceEventStore, StoreProvider} +import gr.grnet.aquarium.store.{StoreProvider} import java.io.File import gr.grnet.aquarium.util.{Loggable, Lifecycle} import gr.grnet.aquarium.service.{StoreWatcherService, RabbitMQService, TimerService, EventBusService, AkkaService} @@ -50,7 +50,8 @@ import com.ckkloverdos.maybe._ import gr.grnet.aquarium.ResourceLocator._ import com.ckkloverdos.sys.SysProp import gr.grnet.aquarium.service.event.AquariumCreatedEvent -import gr.grnet.aquarium.policy.{PolicyDefinedFullPriceTableRef, StdUserAgreement, UserAgreementModel, ResourceType} +import gr.grnet.aquarium.policy.{PolicyHistory, PolicyDefinedFullPriceTableRef, StdUserAgreement, UserAgreementModel, ResourceType} +import gr.grnet.aquarium.charging.ChargingBehavior /** * @@ -60,6 +61,10 @@ import gr.grnet.aquarium.policy.{PolicyDefinedFullPriceTableRef, StdUserAgreemen final class Aquarium(env: Env) extends Lifecycle with Loggable { import Aquarium.EnvKeys + @volatile private[this] var _chargingBehaviorMap = Map[String, ChargingBehavior]() + + private[this] val policyHistory = new PolicyHistory + private[this] val _isStopping = new AtomicBoolean(false) override def toString = "%s/v%s".format(getClass.getName, version) @@ -99,7 +104,7 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable { } } - private[this] lazy val _allServices = Aquarium.ServiceKeys.map(this(_)) + private[this] lazy val _allServices = Aquarium.ServiceKeys.map(this.apply(_)) private[this] def startServices(): Unit = { for(service ← _allServices) { @@ -139,7 +144,7 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable { logger.info("CONF_HERE = {}", HERE) logger.info("{} = {}", ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES, ResourceLocator.Resources.AquariumPropertiesResource) logger.info("{} = {}", ResourceLocator.ResourceNames.LOGBACK_XML, ResourceLocator.Resources.LogbackXMLResource) - logger.info("{} = {}", ResourceLocator.ResourceNames.POLICY_YAML, ResourceLocator.Resources.PolicyYAMLResource) + logger.info("{} = {}", ResourceLocator.ResourceNames.POLICY_JSON, ResourceLocator.Resources.PolicyJSONResource) logger.info("Runtime.getRuntime.availableProcessors() => {}", Runtime.getRuntime.availableProcessors()) } @@ -179,7 +184,14 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable { /** * Reflectively provide a new instance of a class and configure it appropriately. */ - def newInstance[C <: AnyRef](_class: Class[C], className: String): C = { + def newInstance[C <: AnyRef](_class: Class[C]): C = { + newInstance(_class.getName) + } + + /** + * Reflectively provide a new instance of a class and configure it appropriately. + */ + def newInstance[C <: AnyRef](className: String): C = { val originalProps = apply(EnvKeys.originalProps) val instanceM = MaybeEither(defaultClassLoader.loadClass(className).newInstance().asInstanceOf[C]) @@ -248,15 +260,33 @@ final class Aquarium(env: Env) extends Lifecycle with Loggable { "default" } + def chargingBehaviorOf(resourceType: ResourceType): ChargingBehavior = { + val className = resourceType.chargingBehavior + _chargingBehaviorMap.get(className) match { + case Some(chargingBehavior) ⇒ + chargingBehavior + + case _ ⇒ + // It does not matter if this is entered by multiple threads and more than one instance of the same class + // is created. The returned instance is not meant to be cached. + val chargingBehavior = newInstance[ChargingBehavior](className) + _chargingBehaviorMap synchronized { + _chargingBehaviorMap = _chargingBehaviorMap.updated(className, chargingBehavior) + } + + chargingBehavior + } + } + def defaultClassLoader = apply(EnvKeys.defaultClassLoader) - def resourceEventStore = apply(EnvKeys.resourceEventStore) + def resourceEventStore = apply(EnvKeys.storeProvider).resourceEventStore - def imEventStore = apply(EnvKeys.imEventStore) + def imEventStore = apply(EnvKeys.storeProvider).imEventStore - def userStateStore = apply(EnvKeys.userStateStore) + def userStateStore = apply(EnvKeys.storeProvider).userStateStore - def policyStore = apply(EnvKeys.policyStore) + def policyStore = apply(EnvKeys.storeProvider).policyStore def eventsStoreFolder = apply(EnvKeys.eventsStoreFolder) @@ -304,7 +334,7 @@ object Aquarium { } final class AquariumEnvKey[T: Manifest](override val name: String) extends TypedKeySkeleton[T](name) { - override def toString = name + override def toString = "%s(%s)".format(manifest[T], name) } final val ServiceKeys: List[TypedKey[_ <: Lifecycle]] = List( @@ -383,17 +413,17 @@ object Aquarium { final val adminCookie: TypedKey[Option[String]] = new AquariumEnvKey[Option[String]]("admin.cookie") - final val resourceEventStore: TypedKey[ResourceEventStore] = - new AquariumEnvKey[ResourceEventStore]("resource.event.store.class") +// final val resourceEventStore: TypedKey[ResourceEventStore] = +// new AquariumEnvKey[ResourceEventStore]("resource.event.store.class") - final val imEventStore: TypedKey[IMEventStore] = - new AquariumEnvKey[IMEventStore]("im.event.store.class") +// final val imEventStore: TypedKey[IMEventStore] = +// new AquariumEnvKey[IMEventStore]("im.event.store.class") - final val userStateStore: TypedKey[UserStateStore] = - new AquariumEnvKey[UserStateStore]("user.state.store.class") +// final val userStateStore: TypedKey[UserStateStore] = +// new AquariumEnvKey[UserStateStore]("user.state.store.class") - final val policyStore: TypedKey[PolicyStore] = - new AquariumEnvKey[PolicyStore]("policy.store.class") +// final val policyStore: TypedKey[PolicyStore] = +// new AquariumEnvKey[PolicyStore]("policy.store.class") /** * The class that initializes the REST service diff --git a/src/main/scala/gr/grnet/aquarium/AquariumBuilder.scala b/src/main/scala/gr/grnet/aquarium/AquariumBuilder.scala index e1ec73c..2d09905 100644 --- a/src/main/scala/gr/grnet/aquarium/AquariumBuilder.scala +++ b/src/main/scala/gr/grnet/aquarium/AquariumBuilder.scala @@ -38,11 +38,9 @@ package gr.grnet.aquarium import com.ckkloverdos.key.{BooleanKey, TypedKey} import com.ckkloverdos.env.Env import com.ckkloverdos.props.Props -import com.ckkloverdos.maybe.{MaybeOption, Failed, MaybeEither, Just, NoVal} +import com.ckkloverdos.maybe.{Failed, MaybeEither, Just, NoVal} import gr.grnet.aquarium.util.Loggable import java.io.File -import gr.grnet.aquarium.store.StoreProvider -import gr.grnet.aquarium.logic.accounting.algorithm.SimpleCostPolicyAlgorithmCompiler import gr.grnet.aquarium.computation.UserStateComputations import gr.grnet.aquarium.service.{StoreWatcherService, RabbitMQService, AkkaService, SimpleTimerService, EventBusService} import gr.grnet.aquarium.converter.StdConverters @@ -159,8 +157,8 @@ final class AquariumBuilder(val originalProps: Props) extends Loggable { val propName = envKey.name originalProps.get(propName) match { - case Just(propValue) ⇒ - update(envKey, newInstance(envKey.keyType, propValue)) + case Just(storeProviderClassName) ⇒ + update(envKey, newInstance(envKey.keyType, storeProviderClassName)) case NoVal ⇒ throw new AquariumInternalError("No store provider is given in properties") @@ -170,39 +168,6 @@ final class AquariumBuilder(val originalProps: Props) extends Loggable { } } - private[this] def checkStoreOverrides: Unit = { - if(originalProps eq null) { - return - } - - def checkOverride[S <: AnyRef : Manifest](envKey: TypedKey[S], f: StoreProvider ⇒ S): Unit = { - if(!_env.contains(envKey)) { - val propName = envKey.name - - originalProps.get(propName) match { - case Just(propValue) ⇒ - // Create the store reflectively - update(envKey, newInstance(envKey.keyType, propValue)) - - case NoVal ⇒ - // Get the store from the store provider - val storeProvider = this.envGetEx(EnvKeys.storeProvider) - val propValue = f(storeProvider) - update(envKey, propValue) - - case Failed(e) ⇒ - throw new AquariumInternalError(e, "While obtaining value for key %s in properties".format(propName)) - } - } - } - - // If a store has not been specifically overridden, we load it from the properties - checkOverride(EnvKeys.resourceEventStore, _.resourceEventStore) - checkOverride(EnvKeys.imEventStore, _.imEventStore) - checkOverride(EnvKeys.userStateStore, _.userStateStore) - checkOverride(EnvKeys.policyStore, _.policyStore) - } - private[this] def checkEventsStoreFolderOverride: Unit = { val propName = EnvKeys.eventsStoreFolder.name @@ -360,7 +325,6 @@ final class AquariumBuilder(val originalProps: Props) extends Loggable { checkNoPropsOverride(EnvKeys.converters) { _ ⇒ StdConverters.AllConverters } checkStoreProviderOverride - checkStoreOverrides checkEventsStoreFolderOverride checkEventsStoreFolderExistence diff --git a/src/main/scala/gr/grnet/aquarium/Main.scala b/src/main/scala/gr/grnet/aquarium/Main.scala index 65dccac..4500218 100644 --- a/src/main/scala/gr/grnet/aquarium/Main.scala +++ b/src/main/scala/gr/grnet/aquarium/Main.scala @@ -43,6 +43,7 @@ import ch.qos.logback.classic.LoggerContext import ch.qos.logback.classic.joran.JoranConfigurator import com.ckkloverdos.maybe.Just import gr.grnet.aquarium.service.event.AquariumCreatedEvent +import gr.grnet.aquarium.policy.PolicyModel /** * Main method for Aquarium diff --git a/src/main/scala/gr/grnet/aquarium/ResourceLocator.scala b/src/main/scala/gr/grnet/aquarium/ResourceLocator.scala index 4f4bb44..3bd1398 100644 --- a/src/main/scala/gr/grnet/aquarium/ResourceLocator.scala +++ b/src/main/scala/gr/grnet/aquarium/ResourceLocator.scala @@ -35,15 +35,13 @@ package gr.grnet.aquarium -import com.ckkloverdos.maybe.{Failed, Just, Maybe, NoVal} +import com.ckkloverdos.maybe.{Maybe, NoVal} import com.ckkloverdos.sys.{SysEnv, SysProp} import java.io.File import gr.grnet.aquarium.util.justForSure -import gr.grnet.aquarium.util.isRunningTests import com.ckkloverdos.resource.{FileStreamResource, StreamResource, CompositeStreamResourceContext, ClassLoaderStreamResourceContext, FileStreamResourceContext} import com.ckkloverdos.props.Props -import com.ckkloverdos.convert.Converters._ import com.ckkloverdos.maybe.Just import com.ckkloverdos.maybe.Failed import com.ckkloverdos.convert.Converters @@ -51,8 +49,6 @@ import com.ckkloverdos.convert.Converters /** * Locates resources. * - * This code was initially in [[gr.grnet.aquarium.Aquarium]]. - * * @author Christos KK Loverdos */ @@ -63,8 +59,7 @@ object ResourceLocator { final val LOGBACK_XML = "logback.xml" final val AQUARIUM_PROPERTIES = "aquarium.properties" - final val POLICY_YAML = "policy.yaml" - final val ROLE_AGREEMENTS_MAP = "roles-agreements.map" + final val POLICY_JSON = "policy.json" } final object Homes { @@ -256,18 +251,18 @@ object ResourceLocator { } } - final lazy val PolicyYAMLResource = { - ResourceLocator.getResource(ResourceLocator.ResourceNames.POLICY_YAML) match { - case Just(policyYAML) ⇒ - policyYAML + final lazy val PolicyJSONResource = { + ResourceLocator.getResource(ResourceLocator.ResourceNames.POLICY_JSON) match { + case Just(policyJSON) ⇒ + policyJSON case NoVal ⇒ throw new AquariumInternalError( - "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_YAML)) + "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_JSON)) case Failed(e) ⇒ throw new AquariumInternalError( - "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_YAML), e) + "Could not find %s".format(ResourceLocator.ResourceNames.POLICY_JSON), e) } } } diff --git a/src/main/scala/gr/grnet/aquarium/charging/ChargingBehavior.scala b/src/main/scala/gr/grnet/aquarium/charging/ChargingBehavior.scala index eb1c979..4c252e1 100644 --- a/src/main/scala/gr/grnet/aquarium/charging/ChargingBehavior.scala +++ b/src/main/scala/gr/grnet/aquarium/charging/ChargingBehavior.scala @@ -45,7 +45,7 @@ import gr.grnet.aquarium.{AquariumInternalError, AquariumException} * @author Christos KK Loverdos */ -abstract class ChargingBehavior(val name: String, val inputs: Set[ChargingInput]) { +abstract class ChargingBehavior(val alias: String, val inputs: Set[ChargingInput]) { final lazy val inputNames = inputs.map(_.name) @@ -88,7 +88,7 @@ abstract class ChargingBehavior(val name: String, val inputs: Set[ChargingInput] unitPrice) } - def isNamed(aName: String): Boolean = aName == name + def isNamed(aName: String): Boolean = aName == alias def needsPreviousEventForCreditAndAmountCalculation: Boolean = { // If we need any variable that is related to the previous event @@ -180,23 +180,6 @@ abstract class ChargingBehavior(val name: String, val inputs: Set[ChargingInput] } object ChargingBehavior { - def apply(name: String): ChargingBehavior = { - name match { - case null ⇒ - throw new AquariumException(" charging behavior") - - case name ⇒ name.toLowerCase match { - case ChargingBehaviorNames.onoff ⇒ OnOffChargingBehavior - case ChargingBehaviorNames.discrete ⇒ DiscreteChargingBehavior - case ChargingBehaviorNames.continuous ⇒ ContinuousChargingBehavior - case ChargingBehaviorNames.once ⇒ ContinuousChargingBehavior - - case _ ⇒ - throw new AquariumException("Invalid charging behavior %s".format(name)) - } - } - } - def makeValueMapFor( chargingBehavior: ChargingBehavior, totalCredits: Double, @@ -211,7 +194,7 @@ object ChargingBehavior { val inputs = chargingBehavior.inputs var map = Map[ChargingInput, Any]() - if(inputs contains ChargingBehaviorNameInput) map += ChargingBehaviorNameInput -> chargingBehavior.name + if(inputs contains ChargingBehaviorNameInput) map += ChargingBehaviorNameInput -> chargingBehavior.alias if(inputs contains TotalCreditsInput ) map += TotalCreditsInput -> totalCredits if(inputs contains OldTotalAmountInput) map += OldTotalAmountInput -> oldTotalAmount if(inputs contains NewTotalAmountInput) map += NewTotalAmountInput -> newTotalAmount @@ -223,241 +206,3 @@ object ChargingBehavior { map } } - -/** - * 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 OnceChargingBehavior -extends ChargingBehavior( - ChargingBehaviorNames.once, - Set(ChargingBehaviorNameInput, CurrentValueInput) -) { - - /** - * This is called when we have the very first event for a particular resource instance, and we want to know - * if it is billable or not. - */ - def isBillableFirstEvent(event: ResourceEventModel) = { - true - } - - def mustGenerateDummyFirstEvent = false // no need to - - def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]) = { - oldAmount - } - - def getResourceInstanceInitialAmount = 0.0 - - def supportsImplicitEvents = false - - def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = false - - def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, occurredMillis: Long) = { - throw new AquariumException("constructImplicitEndEventFor() Not compliant with %s".format(this)) - } -} - -/** - * In practice a resource usage will be charged for the total amount of usage - * between resource usage changes. - * - * Example resource that might be adept to a continuous policy - * is diskspace. - */ -case object ContinuousChargingBehavior -extends ChargingBehavior( - ChargingBehaviorNames.continuous, - Set(ChargingBehaviorNameInput, UnitPriceInput, OldTotalAmountInput, TimeDeltaInput) -) { - - def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = { - // If the total is in the details, get it, or else compute it - details.get("total") match { - case Some(total) ⇒ - total.toDouble - - case _ ⇒ - oldAmount + newEventValue - } - } - - def getResourceInstanceInitialAmount: Double = { - 0.0 - } - - /** - * This is called when we have the very first event for a particular resource instance, and we want to know - * if it is billable or not. - */ - def isBillableFirstEvent(event: ResourceEventModel) = { - true - } - - def mustGenerateDummyFirstEvent = true - - def supportsImplicitEvents = { - true - } - - def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = { - true - } - - def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, newOccurredMillis: Long) = { - assert(supportsImplicitEvents && mustConstructImplicitEndEventFor(resourceEvent)) - - val details = resourceEvent.details - val newDetails = ResourceEventModel.setAquariumSyntheticAndImplicitEnd(details) - - resourceEvent.withDetails(newDetails, newOccurredMillis) - } -} - -/** - * 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 - * the timeframes within the resource is in the `off` state. - * - * Example resources that might be adept to onoff policies are VMs in a - * cloud application and books in a book lending application. - */ -case object OnOffChargingBehavior -extends ChargingBehavior( - ChargingBehaviorNames.onoff, - Set(ChargingBehaviorNameInput, UnitPriceInput, TimeDeltaInput) -) { - - /** - * - * @param oldAmount is ignored - * @param newEventValue - * @return - */ - def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = { - newEventValue - } - - def getResourceInstanceInitialAmount: Double = { - 0.0 - } - - private[this] - def getValueForCreditCalculation(oldAmount: Double, newEventValue: Double): Double = { - import OnOffChargingBehaviorValues.{ON, OFF} - - def exception(rs: OnOffPolicyResourceState) = - new AquariumException("Resource state transition error (%s -> %s)".format(rs, rs)) - - (oldAmount, newEventValue) match { - case (ON, ON) ⇒ - throw exception(OnResourceState) - case (ON, OFF) ⇒ - OFF - case (OFF, ON) ⇒ - ON - case (OFF, OFF) ⇒ - throw exception(OffResourceState) - } - } - - override def isBillableEvent(event: ResourceEventModel) = { - // ON events do not contribute, only OFF ones. - OnOffChargingBehaviorValues.isOFFValue(event.value) - } - - /** - * This is called when we have the very first event for a particular resource instance, and we want to know - * if it is billable or not. - */ - def isBillableFirstEvent(event: ResourceEventModel) = { - false - } - - def mustGenerateDummyFirstEvent = false // should be handled by the implicit OFFs - - def supportsImplicitEvents = { - true - } - - 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. - OnOffChargingBehaviorValues.isONValue(resourceEvent.value) - } - - def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, newOccurredMillis: Long) = { - assert(supportsImplicitEvents && mustConstructImplicitEndEventFor(resourceEvent)) - assert(OnOffChargingBehaviorValues.isONValue(resourceEvent.value)) - - val details = resourceEvent.details - val newDetails = ResourceEventModel.setAquariumSyntheticAndImplicitEnd(details) - val newValue = OnOffChargingBehaviorValues.OFF - - resourceEvent.withDetailsAndValue(newDetails, newValue, newOccurredMillis) - } - - def constructImplicitStartEventFor(resourceEvent: ResourceEventModel) = { - throw new AquariumInternalError("constructImplicitStartEventFor() Not compliant with %s".format(this)) - } -} - -object OnOffChargingBehaviorValues { - final val ON = 1.0 - final val OFF = 0.0 - - def isONValue (value: Double) = value == ON - def isOFFValue(value: Double) = value == OFF -} - -/** - * 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. - * - * Example oneoff resources might be individual charges applied to various - * 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 DiscreteChargingBehavior -extends ChargingBehavior( - ChargingBehaviorNames.discrete, - Set(ChargingBehaviorNameInput, UnitPriceInput, CurrentValueInput) -) { - - def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = { - oldAmount + newEventValue - } - - def getResourceInstanceInitialAmount: Double = { - 0.0 - } - - /** - * This is called when we have the very first event for a particular resource instance, and we want to know - * if it is billable or not. - */ - def isBillableFirstEvent(event: ResourceEventModel) = { - false // nope, we definitely need a previous one. - } - - // FIXME: Check semantics of this. I just put false until thorough study - def mustGenerateDummyFirstEvent = false - - def supportsImplicitEvents = { - false - } - - def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = { - false - } - - def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, occurredMillis: Long) = { - throw new AquariumInternalError("constructImplicitEndEventFor() Not compliant with %s".format(this)) - } -} diff --git a/src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorNames.scala b/src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorAliases.scala similarity index 98% rename from src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorNames.scala rename to src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorAliases.scala index 1908f75..6699d8e 100644 --- a/src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorNames.scala +++ b/src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorAliases.scala @@ -40,7 +40,7 @@ package gr.grnet.aquarium.charging * @author Christos KK Loverdos */ -object ChargingBehaviorNames { +object ChargingBehaviorAliases { final val onoff = "onoff" final val discrete = "discrete" final val continuous = "continuous" diff --git a/src/main/scala/gr/grnet/aquarium/charging/ContinuousChargingBehavior.scala b/src/main/scala/gr/grnet/aquarium/charging/ContinuousChargingBehavior.scala new file mode 100644 index 0000000..473d88d --- /dev/null +++ b/src/main/scala/gr/grnet/aquarium/charging/ContinuousChargingBehavior.scala @@ -0,0 +1,101 @@ +/* + * 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.event.model.resource.ResourceEventModel + +/** + * In practice a resource usage will be charged for the total amount of usage + * between resource usage changes. + * + * Example resource that might be adept to a continuous policy + * is diskspace. + * + * @author Christos KK Loverdos + */ +final class ContinuousChargingBehavior + extends ChargingBehavior( + ChargingBehaviorAliases.continuous, + Set(ChargingBehaviorNameInput, UnitPriceInput, OldTotalAmountInput, TimeDeltaInput)) { + + def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = { + // If the total is in the details, get it, or else compute it + details.get("total") match { + case Some(total) ⇒ + total.toDouble + + case _ ⇒ + oldAmount + newEventValue + } + } + + def getResourceInstanceInitialAmount: Double = { + 0.0 + } + + /** + * This is called when we have the very first event for a particular resource instance, and we want to know + * if it is billable or not. + */ + def isBillableFirstEvent(event: ResourceEventModel) = { + true + } + + def mustGenerateDummyFirstEvent = true + + def supportsImplicitEvents = { + true + } + + def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = { + true + } + + def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, newOccurredMillis: Long) = { + assert(supportsImplicitEvents && mustConstructImplicitEndEventFor(resourceEvent)) + + val details = resourceEvent.details + val newDetails = ResourceEventModel.setAquariumSyntheticAndImplicitEnd(details) + + resourceEvent.withDetails(newDetails, newOccurredMillis) + } +} + +object ContinuousChargingBehavior { + private[this] final val TheOne = new ContinuousChargingBehavior + + def apply(): ContinuousChargingBehavior = TheOne +} diff --git a/src/main/scala/gr/grnet/aquarium/charging/DiscreteChargingBehavior.scala b/src/main/scala/gr/grnet/aquarium/charging/DiscreteChargingBehavior.scala new file mode 100644 index 0000000..178237f --- /dev/null +++ b/src/main/scala/gr/grnet/aquarium/charging/DiscreteChargingBehavior.scala @@ -0,0 +1,93 @@ +/* + * 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.event.model.resource.ResourceEventModel +import gr.grnet.aquarium.AquariumInternalError + +/** + * 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. + * + * Example oneoff resources might be individual charges applied to various + * 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) + * + * @author Christos KK Loverdos + */ +final class DiscreteChargingBehavior + extends ChargingBehavior( + ChargingBehaviorAliases.discrete, + Set(ChargingBehaviorNameInput, UnitPriceInput, CurrentValueInput)) { + + def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = { + oldAmount + newEventValue + } + + def getResourceInstanceInitialAmount: Double = { + 0.0 + } + + /** + * This is called when we have the very first event for a particular resource instance, and we want to know + * if it is billable or not. + */ + def isBillableFirstEvent(event: ResourceEventModel) = { + false // nope, we definitely need a previous one. + } + + // FIXME: Check semantics of this. I just put false until thorough study + def mustGenerateDummyFirstEvent = false + + def supportsImplicitEvents = { + false + } + + def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = { + false + } + + def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, occurredMillis: Long) = { + throw new AquariumInternalError("constructImplicitEndEventFor() Not compliant with %s".format(this)) + } +} + +object DiscreteChargingBehavior { + private[this] final val TheOne = new DiscreteChargingBehavior + + def apply(): DiscreteChargingBehavior = TheOne +} diff --git a/src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehavior.scala b/src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehavior.scala new file mode 100644 index 0000000..e84e269 --- /dev/null +++ b/src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehavior.scala @@ -0,0 +1,136 @@ +/* + * 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.{AquariumInternalError, AquariumException} +import gr.grnet.aquarium.event.model.resource.ResourceEventModel + +/** + * 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 + * the timeframes within the resource is in the `off` state. + * + * Example resources that might be adept to onoff policies are VMs in a + * cloud application and books in a book lending application. + * + * @author Christos KK Loverdos + */ +final class OnOffChargingBehavior + extends ChargingBehavior( + ChargingBehaviorAliases.onoff, + Set(ChargingBehaviorNameInput, UnitPriceInput, TimeDeltaInput)) { + + /** + * + * @param oldAmount is ignored + * @param newEventValue + * @return + */ + def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]): Double = { + newEventValue + } + + def getResourceInstanceInitialAmount: Double = { + 0.0 + } + + private[this] + def getValueForCreditCalculation(oldAmount: Double, newEventValue: Double): Double = { + import OnOffChargingBehaviorValues.{ON, OFF} + + def exception(rs: OnOffPolicyResourceState) = + new AquariumException("Resource state transition error (%s -> %s)".format(rs, rs)) + + (oldAmount, newEventValue) match { + case (ON, ON) ⇒ + throw exception(OnResourceState) + case (ON, OFF) ⇒ + OFF + case (OFF, ON) ⇒ + ON + case (OFF, OFF) ⇒ + throw exception(OffResourceState) + } + } + + override def isBillableEvent(event: ResourceEventModel) = { + // ON events do not contribute, only OFF ones. + OnOffChargingBehaviorValues.isOFFValue(event.value) + } + + /** + * This is called when we have the very first event for a particular resource instance, and we want to know + * if it is billable or not. + */ + def isBillableFirstEvent(event: ResourceEventModel) = { + false + } + + def mustGenerateDummyFirstEvent = false // should be handled by the implicit OFFs + + def supportsImplicitEvents = { + true + } + + 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. + OnOffChargingBehaviorValues.isONValue(resourceEvent.value) + } + + def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, newOccurredMillis: Long) = { + assert(supportsImplicitEvents && mustConstructImplicitEndEventFor(resourceEvent)) + assert(OnOffChargingBehaviorValues.isONValue(resourceEvent.value)) + + val details = resourceEvent.details + val newDetails = ResourceEventModel.setAquariumSyntheticAndImplicitEnd(details) + val newValue = OnOffChargingBehaviorValues.OFF + + resourceEvent.withDetailsAndValue(newDetails, newValue, newOccurredMillis) + } + + def constructImplicitStartEventFor(resourceEvent: ResourceEventModel) = { + throw new AquariumInternalError("constructImplicitStartEventFor() Not compliant with %s".format(this)) + } +} + +object OnOffChargingBehavior { + private[this] final val TheOne = new OnOffChargingBehavior + + def apply(): OnOffChargingBehavior = TheOne +} diff --git a/src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceStateNames.scala b/src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehaviorValues.scala similarity index 90% rename from src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceStateNames.scala rename to src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehaviorValues.scala index 904597c..1164ccb 100644 --- a/src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceStateNames.scala +++ b/src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehaviorValues.scala @@ -40,7 +40,11 @@ package gr.grnet.aquarium.charging * @author Christos KK Loverdos */ -object OnOffPolicyResourceStateNames { - final val on = "on" - final val off = "off" +object OnOffChargingBehaviorValues { + final val ON = 1.0 + final val OFF = 0.0 + + def isONValue (value: Double) = value == ON + def isOFFValue(value: Double) = value == OFF } + diff --git a/src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceState.scala b/src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceState.scala index 4e3d3a1..2ae9a96 100644 --- a/src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceState.scala +++ b/src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceState.scala @@ -49,25 +49,18 @@ sealed abstract class OnOffPolicyResourceState(val state: String) { def isOff: Boolean = !isOn } -object OnResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.on) { +object OnResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceState.Names.on) { override def isOn = true } -object OffResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceStateNames.off) { +object OffResourceState extends OnOffPolicyResourceState(OnOffPolicyResourceState.Names.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)) - } + object Names { + final val on = "on" + final val off = "off" } } diff --git a/src/main/scala/gr/grnet/aquarium/charging/OnceChargingBehavior.scala b/src/main/scala/gr/grnet/aquarium/charging/OnceChargingBehavior.scala new file mode 100644 index 0000000..1a1213d --- /dev/null +++ b/src/main/scala/gr/grnet/aquarium/charging/OnceChargingBehavior.scala @@ -0,0 +1,82 @@ +/* + * 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.event.model.resource.ResourceEventModel +import gr.grnet.aquarium.AquariumException + +/** + * 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. + * + * @author Christos KK Loverdos + */ +final class OnceChargingBehavior + extends ChargingBehavior( + ChargingBehaviorAliases.once, + Set(ChargingBehaviorNameInput, CurrentValueInput)) { + + /** + * This is called when we have the very first event for a particular resource instance, and we want to know + * if it is billable or not. + */ + def isBillableFirstEvent(event: ResourceEventModel) = { + true + } + + def mustGenerateDummyFirstEvent = false // no need to + + def computeNewAccumulatingAmount(oldAmount: Double, newEventValue: Double, details: Map[String, String]) = { + oldAmount + } + + def getResourceInstanceInitialAmount = 0.0 + + def supportsImplicitEvents = false + + def mustConstructImplicitEndEventFor(resourceEvent: ResourceEventModel) = false + + def constructImplicitEndEventFor(resourceEvent: ResourceEventModel, occurredMillis: Long) = { + throw new AquariumException("constructImplicitEndEventFor() Not compliant with %s".format(this)) + } +} + +object OnceChargingBehavior { + private[this] final val TheOne = new OnceChargingBehavior + + def apply(): OnceChargingBehavior = TheOne +} diff --git a/src/main/scala/gr/grnet/aquarium/computation/TimeslotComputations.scala b/src/main/scala/gr/grnet/aquarium/computation/TimeslotComputations.scala index d5cabe1..09714b3 100644 --- a/src/main/scala/gr/grnet/aquarium/computation/TimeslotComputations.scala +++ b/src/main/scala/gr/grnet/aquarium/computation/TimeslotComputations.scala @@ -40,7 +40,7 @@ import com.ckkloverdos.maybe.{NoVal, Maybe} import gr.grnet.aquarium.util.{ContextualLogger, Loggable} import gr.grnet.aquarium.store.PolicyStore import gr.grnet.aquarium.util.date.MutableDateCalc -import gr.grnet.aquarium.AquariumInternalError +import gr.grnet.aquarium.{Aquarium, AquariumInternalError} import gr.grnet.aquarium.event.model.resource.ResourceEventModel import gr.grnet.aquarium.logic.accounting.algorithm.SimpleExecutableChargingBehaviorAlgorithm import gr.grnet.aquarium.logic.accounting.dsl.Timeslot @@ -170,6 +170,7 @@ trait TimeslotComputations extends Loggable { * */ def computeFullChargeslots( + aquarium: Aquarium, previousResourceEventOpt: Option[ResourceEventModel], currentResourceEvent: ResourceEventModel, oldCredits: Double, @@ -186,7 +187,7 @@ trait TimeslotComputations extends Loggable { val occurredDate = currentResourceEvent.occurredDate val occurredMillis = currentResourceEvent.occurredMillis - val chargingBehavior = resourceType.chargingBehavior + val chargingBehavior = aquarium.chargingBehaviorOf(resourceType) val (referenceTimeslot, policyByTimeslot, previousValue) = chargingBehavior.needsPreviousEventForCreditAndAmountCalculation match { // We need a previous event diff --git a/src/main/scala/gr/grnet/aquarium/computation/UserStateComputations.scala b/src/main/scala/gr/grnet/aquarium/computation/UserStateComputations.scala index b2e8677..6d7cb76 100644 --- a/src/main/scala/gr/grnet/aquarium/computation/UserStateComputations.scala +++ b/src/main/scala/gr/grnet/aquarium/computation/UserStateComputations.scala @@ -203,7 +203,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable { resourceTypesMap.get(theResource) match { // We have a resource type (and thus a charging behavior) case Some(resourceType) ⇒ - val chargingBehavior = resourceType.chargingBehavior + val chargingBehavior = aquarium.chargingBehaviorOf(resourceType) clog.debug("%s for %s", chargingBehavior, resourceType) val isBillable = chargingBehavior.isBillableEvent(currentResourceEvent) if(!isBillable) { @@ -265,6 +265,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable { // clog.debug("Computing full chargeslots") val (referenceTimeslot, fullChargeslots) = timeslotComputations.computeFullChargeslots( + aquarium, previousResourceEventOpt1, currentResourceEvent, oldCredits, @@ -469,7 +470,7 @@ final class UserStateComputations extends AquariumAwareSkeleton with Loggable { // Second, for the remaining events which must contribute an implicit OFF, we collect those OFFs // ... in order to generate an implicit ON later (during the next billing cycle). val (specialEvents, theirImplicitEnds) = userStateWorker. - findAndRemoveGeneratorsOfImplicitEndEvents(billingMonthInfo.monthStopMillis) + findAndRemoveGeneratorsOfImplicitEndEvents(aquarium, billingMonthInfo.monthStopMillis) if(specialEvents.lengthCompare(1) >= 0 || theirImplicitEnds.lengthCompare(1) >= 0) { clog.debug("") diff --git a/src/main/scala/gr/grnet/aquarium/computation/state/UserStateWorker.scala b/src/main/scala/gr/grnet/aquarium/computation/state/UserStateWorker.scala index bb0692f..40c2e71 100644 --- a/src/main/scala/gr/grnet/aquarium/computation/state/UserStateWorker.scala +++ b/src/main/scala/gr/grnet/aquarium/computation/state/UserStateWorker.scala @@ -41,6 +41,7 @@ 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 +import gr.grnet.aquarium.Aquarium /** * A helper object holding intermediate state/results during resource event processing. @@ -144,6 +145,7 @@ case class UserStateWorker( * @see [[gr.grnet.aquarium.charging.ChargingBehavior]] */ def findAndRemoveGeneratorsOfImplicitEndEvents( + aquarium: Aquarium, /** * The `occurredMillis` that will be recorded in the synthetic implicit OFFs. * Normally, this will be the end of a billing month. @@ -159,7 +161,7 @@ case class UserStateWorker( for { resourceEvent ← resourceEvents resourceType ← resourceTypesMap.get(resourceEvent.safeResource) - chargingBehavior = resourceType.chargingBehavior + chargingBehavior = aquarium.chargingBehaviorOf(resourceType) } { if(chargingBehavior.supportsImplicitEvents) { if(chargingBehavior.mustConstructImplicitEndEventFor(resourceEvent)) { diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm$.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm.scala similarity index 82% rename from src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm$.scala rename to src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm.scala index b5fa6e2..2f4c6b9 100644 --- a/src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm$.scala +++ b/src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm.scala @@ -36,10 +36,8 @@ package gr.grnet.aquarium.logic.accounting.algorithm -import com.ckkloverdos.maybe.Maybe -import gr.grnet.aquarium.logic.accounting.dsl._ import gr.grnet.aquarium.AquariumException -import gr.grnet.aquarium.charging.{CurrentValueInput, TimeDeltaInput, OldTotalAmountInput, UnitPriceInput, ChargingBehaviorNames, ChargingBehaviorNameInput, ChargingInput} +import gr.grnet.aquarium.charging.{CurrentValueInput, TimeDeltaInput, OldTotalAmountInput, UnitPriceInput, ChargingBehaviorAliases, ChargingBehaviorNameInput, ChargingInput} /** * An executable charging algorithm with some simple implementation. @@ -53,26 +51,26 @@ object SimpleExecutableChargingBehaviorAlgorithm extends ExecutableChargingBehav def apply(vars: Map[ChargingInput, Any]): Double = { vars.apply(ChargingBehaviorNameInput) match { - case ChargingBehaviorNames.continuous ⇒ + case ChargingBehaviorAliases.continuous ⇒ val unitPrice = vars(UnitPriceInput).asInstanceOf[Double] val oldTotalAmount = vars(OldTotalAmountInput).asInstanceOf[Double] val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double] hrs(timeDelta) * oldTotalAmount * unitPrice - case ChargingBehaviorNames.discrete ⇒ + case ChargingBehaviorAliases.discrete ⇒ val unitPrice = vars(UnitPriceInput).asInstanceOf[Double] val currentValue = vars(CurrentValueInput).asInstanceOf[Double] currentValue * unitPrice - case ChargingBehaviorNames.onoff ⇒ + case ChargingBehaviorAliases.onoff ⇒ val unitPrice = vars(UnitPriceInput).asInstanceOf[Double] val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double] hrs(timeDelta) * unitPrice - case ChargingBehaviorNames.once ⇒ + case ChargingBehaviorAliases.once ⇒ val currentValue = vars(CurrentValueInput).asInstanceOf[Double] currentValue @@ -83,8 +81,8 @@ object SimpleExecutableChargingBehaviorAlgorithm extends ExecutableChargingBehav override def toString = "SimpleExecutableCostPolicyAlgorithm(%s)".format( Map( - ChargingBehaviorNames.continuous -> "hrs(timeDelta) * oldTotalAmount * unitPrice", - ChargingBehaviorNames.discrete -> "currentValue * unitPrice", - ChargingBehaviorNames.onoff -> "hrs(timeDelta) * unitPrice", - ChargingBehaviorNames.once -> "currentValue")) + ChargingBehaviorAliases.continuous -> "hrs(timeDelta) * oldTotalAmount * unitPrice", + ChargingBehaviorAliases.discrete -> "currentValue * unitPrice", + ChargingBehaviorAliases.onoff -> "hrs(timeDelta) * unitPrice", + ChargingBehaviorAliases.once -> "currentValue")) } diff --git a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Timeslot.scala b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Timeslot.scala index c81f867..8168faf 100644 --- a/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Timeslot.scala +++ b/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Timeslot.scala @@ -82,7 +82,6 @@ final case class Timeslot(from: Date, to: Date) extends Ordered[Timeslot] { */ private[dsl] def includes(t: Date) : Boolean = start <= t.getTime && t.getTime <= end - private[dsl] def weakIncludes(t: Date) : Boolean = start < t.getTime && t.getTime < end /** * Check whether this timeslot overlaps with the provided one. @@ -90,8 +89,6 @@ final case class Timeslot(from: Date, to: Date) extends Ordered[Timeslot] { def overlaps(t: Timeslot) : Boolean = contains(t) || t.contains(this) || this.includes(t.from) || this.includes(t.to) - def weakOverlaps(t: Timeslot) : Boolean = - contains(t) || t.contains(this) || this.weakIncludes(t.from) || this.weakIncludes(t.to) /** * Merges this timeslot with the provided one. If the timeslots overlap, diff --git a/src/main/scala/gr/grnet/aquarium/policy/EffectiveUnitPrice.scala b/src/main/scala/gr/grnet/aquarium/policy/EffectiveUnitPrice.scala index 37fb7ae..b0f7ac7 100644 --- a/src/main/scala/gr/grnet/aquarium/policy/EffectiveUnitPrice.scala +++ b/src/main/scala/gr/grnet/aquarium/policy/EffectiveUnitPrice.scala @@ -37,7 +37,6 @@ package gr.grnet.aquarium.policy import gr.grnet.aquarium.logic.accounting.dsl.Timeslot import collection.mutable -import java.util /** * @@ -71,7 +70,7 @@ case class EffectiveUnitPrice(unitPrice: Double, when: Option[(CronSpec,CronSpec false case Some(d_end) => result += Timeslot(d_start,d_end) - offset = d_end //new util.Date(d_end.getTime + 1000L) + offset = d_end d_end.before(t.to) } }) () @@ -90,6 +89,6 @@ case class EffectiveUnitPrice(unitPrice: Double, when: Option[(CronSpec,CronSpec case None => "? ? ? ? ?" case Some((_,s)) => s.toString } - override def toString : String = "EffectiveUnitPrice(%d,%s,%s)". + override def toString : String = "EffectiveUnitPrice(%f,%s,%s)". format(unitPrice,stringOfStartCron,stringOfEndCron) } diff --git a/src/main/scala/gr/grnet/aquarium/policy/PolicyHistory.scala b/src/main/scala/gr/grnet/aquarium/policy/PolicyHistory.scala new file mode 100644 index 0000000..e15a901 --- /dev/null +++ b/src/main/scala/gr/grnet/aquarium/policy/PolicyHistory.scala @@ -0,0 +1,70 @@ +/* + * 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 scala.collection.immutable.TreeSet +import gr.grnet.aquarium.Timespan +import gr.grnet.aquarium.util.Lock + +/** + * A mutable container of policy models. + * + * @author Christos KK Loverdos + */ + +class PolicyHistory { + private[this] val lock = new Lock() + @volatile private[this] var _policies = TreeSet[PolicyModel]() + + def insertNewPolicy(newPolicy: PolicyModel): Unit = { + lock.withLock(_policies += newPolicy) + } + + /** + * Return the last (ordered) policy that starts before timeMillis + * + * @param timeMillis + * @return + */ + def findPolicyAt(timeMillis: Long): Option[PolicyModel] = { + lock.withLock { + // Take the subset of all ordered policies up to the one with less than or equal start time + // and then return the last item. This should be the policy right before the given time. + // TODO: optimize the creation of the fake StdPolicy + _policies.to(new StdPolicy("", None, Timespan(timeMillis), Set(), Set(), Map())).lastOption + } + } +} diff --git a/src/main/scala/gr/grnet/aquarium/policy/PolicyModel.scala b/src/main/scala/gr/grnet/aquarium/policy/PolicyModel.scala index 7e6fa50..f5e9eb7 100644 --- a/src/main/scala/gr/grnet/aquarium/policy/PolicyModel.scala +++ b/src/main/scala/gr/grnet/aquarium/policy/PolicyModel.scala @@ -49,14 +49,23 @@ import gr.grnet.aquarium.charging.ChargingBehavior * @author Christos KK Loverdos */ -trait PolicyModel extends JsonSupport { +trait PolicyModel extends Ordered[PolicyModel] with JsonSupport { + final def compare(that: PolicyModel): Int = { + if(this.validFrom < that.validFrom) { + -1 + } else if(this.validFrom == that.validFrom) { + 0 + } else { + 1 + } + } + def id: String def parentID: Option[String] def idInStore: Option[Any] - /** * The time period within which this policy is valid. */ @@ -77,7 +86,7 @@ trait PolicyModel extends JsonSupport { * 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*/] + def chargingBehaviors: Set[String/*ImplementationClassName*/] /** * Each role is mapped to a full price table. diff --git a/src/main/scala/gr/grnet/aquarium/policy/ResourceType.scala b/src/main/scala/gr/grnet/aquarium/policy/ResourceType.scala index d01da5e..7545903 100644 --- a/src/main/scala/gr/grnet/aquarium/policy/ResourceType.scala +++ b/src/main/scala/gr/grnet/aquarium/policy/ResourceType.scala @@ -35,15 +35,15 @@ 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. + * @param chargingBehavior The fully qualified name of the [[gr.grnet.aquarium.charging.ChargingBehavior]] + * implementation used for this resource type. * * @author Christos KK Loverdos */ -case class ResourceType(name: String, unit: String, chargingBehavior: ChargingBehavior) +case class ResourceType(name: String, unit: String, chargingBehavior: String) diff --git a/src/main/scala/gr/grnet/aquarium/policy/StdPolicy.scala b/src/main/scala/gr/grnet/aquarium/policy/StdPolicy.scala index ce3239a..0b0667b 100644 --- a/src/main/scala/gr/grnet/aquarium/policy/StdPolicy.scala +++ b/src/main/scala/gr/grnet/aquarium/policy/StdPolicy.scala @@ -48,7 +48,7 @@ case class StdPolicy( parentID: Option[String], validityTimespan: Timespan, resourceTypes: Set[ResourceType], - chargingBehaviorClasses: Set[String], + chargingBehaviors: Set[String], roleMapping: Map[String/*Role*/, FullPriceTable] ) extends PolicyModel { diff --git a/src/main/scala/gr/grnet/aquarium/service/AkkaService.scala b/src/main/scala/gr/grnet/aquarium/service/AkkaService.scala index 1b86d54..bcd574f 100644 --- a/src/main/scala/gr/grnet/aquarium/service/AkkaService.scala +++ b/src/main/scala/gr/grnet/aquarium/service/AkkaService.scala @@ -223,7 +223,7 @@ final class AkkaService extends AquariumAwareSkeleton with Configurable with Lif // Create new User Actor instance logger.debug("Creating new UserActor instance for %s".format(userID)) val actorRef = _actorSystem.actorOf(Props.apply({ - aquarium.newInstance(classOf[UserActor], classOf[UserActor].getName) + aquarium.newInstance(classOf[UserActor]) }), "userActor::%s".format(userID)) // Cache it for subsequent calls diff --git a/src/main/scala/gr/grnet/aquarium/service/FinagleRESTService.scala b/src/main/scala/gr/grnet/aquarium/service/FinagleRESTService.scala index 2602e0f..553e96f 100644 --- a/src/main/scala/gr/grnet/aquarium/service/FinagleRESTService.scala +++ b/src/main/scala/gr/grnet/aquarium/service/FinagleRESTService.scala @@ -275,7 +275,7 @@ class FinagleRESTService extends Lifecycle with AquariumAwareSkeleton with Confi stringResponseOK("%s\n%s\n%s\n" .format( ResourceLocator.ResourceNames.AQUARIUM_PROPERTIES, ResourceLocator.ResourceNames.LOGBACK_XML, - ResourceLocator.ResourceNames.POLICY_YAML), + ResourceLocator.ResourceNames.POLICY_JSON), TEXT_PLAIN) case RESTPaths.ResourcesAquariumPropertiesPath() ⇒ @@ -284,8 +284,8 @@ class FinagleRESTService extends Lifecycle with AquariumAwareSkeleton with Confi case RESTPaths.ResourcesLogbackXMLPath() ⇒ resourceInfoResponse(ResourceLocator.Resources.LogbackXMLResource, TEXT_PLAIN) - case RESTPaths.ResourcesPolicyYAMLPath() ⇒ - resourceInfoResponse(ResourceLocator.Resources.PolicyYAMLResource, TEXT_PLAIN) + case RESTPaths.ResourcesPolicyJSONPath() ⇒ + resourceInfoResponse(ResourceLocator.Resources.PolicyJSONResource, TEXT_PLAIN) } val EventsHandler: URIPF = { diff --git a/src/main/scala/gr/grnet/aquarium/service/RESTPaths.scala b/src/main/scala/gr/grnet/aquarium/service/RESTPaths.scala index 00e9b9f..3717583 100644 --- a/src/main/scala/gr/grnet/aquarium/service/RESTPaths.scala +++ b/src/main/scala/gr/grnet/aquarium/service/RESTPaths.scala @@ -57,7 +57,7 @@ object RESTPaths { final val ResourcesLogbackXMLPath = toResourcesPath(ResourceLocator.ResourceNames.LOGBACK_XML).r - final val ResourcesPolicyYAMLPath = toResourcesPath(ResourceLocator.ResourceNames.POLICY_YAML).r + final val ResourcesPolicyJSONPath = toResourcesPath(ResourceLocator.ResourceNames.POLICY_JSON).r final val ResourceEventPath = toEventPath("rcevent").r diff --git a/src/main/scala/gr/grnet/aquarium/service/StoreWatcherService.scala b/src/main/scala/gr/grnet/aquarium/service/StoreWatcherService.scala index 271a409..a5bc21f 100644 --- a/src/main/scala/gr/grnet/aquarium/service/StoreWatcherService.scala +++ b/src/main/scala/gr/grnet/aquarium/service/StoreWatcherService.scala @@ -119,6 +119,8 @@ final class StoreWatcherService extends Lifecycle with Configurable with Aquariu val tag = Tags.ResourceEventTag logger.info("Scheduling ping for %s store".format(tag)) + logger.info("AQUARIUM = {}", aquarium) + logger.info("AQUARIUM.resourceEventStore = {}", aquarium.resourceEventStore) doSchedulePing( tag, diff --git a/src/main/scala/gr/grnet/aquarium/simulation/ResourceSim.scala b/src/main/scala/gr/grnet/aquarium/simulation/ResourceSim.scala index f9bf56d..abf2f34 100644 --- a/src/main/scala/gr/grnet/aquarium/simulation/ResourceSim.scala +++ b/src/main/scala/gr/grnet/aquarium/simulation/ResourceSim.scala @@ -46,7 +46,7 @@ import gr.grnet.aquarium.charging.ChargingBehavior * @author Christos KK Loverdos */ -class ResourceSim(val name: String, val unit: String, val chargingBehavior: ChargingBehavior ) { +class ResourceSim(val name: String, val unit: String, val chargingBehavior: String) { def toResourceType = ResourceType(name, unit, chargingBehavior) @@ -61,7 +61,7 @@ class ResourceSim(val name: String, val unit: String, val chargingBehavior: Char object ResourceSim { def apply(name: String, unit: String, chargingBehavior: ChargingBehavior) = { - new ResourceSim(name, unit, chargingBehavior) + new ResourceSim(name, unit, chargingBehavior.getClass.getName) } } diff --git a/src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthResourceSim.scala b/src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthResourceSim.scala index c722649..117af66 100644 --- a/src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthResourceSim.scala +++ b/src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthResourceSim.scala @@ -47,8 +47,8 @@ import gr.grnet.aquarium.charging.{DiscreteChargingBehavior, ChargingBehavior} class StdBandwidthResourceSim( name: String = StdVMTimeResourceSim.DSLNames.name, unit: String = StdVMTimeResourceSim.DSLNames.unit, - costPolicy: ChargingBehavior = DiscreteChargingBehavior -) extends ResourceSim(name, unit, costPolicy) { + chargingBehavior: String = classOf[DiscreteChargingBehavior].getName +) extends ResourceSim(name, unit, chargingBehavior) { override def newInstance(instanceId: String, owner: UserSim, client: ClientSim) = StdBandwidthInstanceSim(this, instanceId, owner, client) diff --git a/src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceResourceSim.scala b/src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceResourceSim.scala index 3abe3e8..97d4813 100644 --- a/src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceResourceSim.scala +++ b/src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceResourceSim.scala @@ -47,7 +47,7 @@ import gr.grnet.aquarium.charging.{ContinuousChargingBehavior, ChargingBehavior} class StdDiskspaceResourceSim( name: String = StdVMTimeResourceSim.DSLNames.name, unit: String = StdVMTimeResourceSim.DSLNames.unit, - chargingBehavior: ChargingBehavior = ContinuousChargingBehavior + chargingBehavior: String = classOf[ContinuousChargingBehavior].getName ) extends ResourceSim(name, unit, chargingBehavior) { override def newInstance(instanceId: String, owner: UserSim, client: ClientSim) = diff --git a/src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeResourceSim.scala b/src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeResourceSim.scala index d15e18b..a65537b 100644 --- a/src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeResourceSim.scala +++ b/src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeResourceSim.scala @@ -48,7 +48,7 @@ import gr.grnet.aquarium.charging.{OnOffChargingBehavior, ChargingBehavior} class StdVMTimeResourceSim( name: String = StdVMTimeResourceSim.DSLNames.name, unit: String = StdVMTimeResourceSim.DSLNames.unit, - chargingBehavior: ChargingBehavior = OnOffChargingBehavior + chargingBehavior: String = classOf[OnOffChargingBehavior].getName ) extends ResourceSim(name, unit, chargingBehavior) { override def newInstance(instanceId: String, owner: UserSim, client: ClientSim) = diff --git a/src/main/scala/gr/grnet/aquarium/store/memory/MemStoreProvider.scala b/src/main/scala/gr/grnet/aquarium/store/memory/MemStoreProvider.scala index f58fe3d..e513606 100644 --- a/src/main/scala/gr/grnet/aquarium/store/memory/MemStoreProvider.scala +++ b/src/main/scala/gr/grnet/aquarium/store/memory/MemStoreProvider.scala @@ -279,7 +279,7 @@ extends StoreProvider parentID = policy.parentID, validityTimespan = policy.validityTimespan, resourceTypes = policy.resourceTypes, - chargingBehaviorClasses = policy.chargingBehaviorClasses, + chargingBehaviors = policy.chargingBehaviors, roleMapping = policy.roleMapping ) _policies = localPolicy :: _policies diff --git a/src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBPolicy.scala b/src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBPolicy.scala index bf7150b..576ef86 100644 --- a/src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBPolicy.scala +++ b/src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBPolicy.scala @@ -45,14 +45,14 @@ import gr.grnet.aquarium.policy.{PolicyModel, FullPriceTable, ResourceType} case class MongoDBPolicy( _id: String, - id: String, parentID: Option[String], validityTimespan: Timespan, resourceTypes: Set[ResourceType], - chargingBehaviorClasses: Set[String], + chargingBehaviors: Set[String], roleMapping: Map[String/*Role*/, FullPriceTable] ) extends PolicyModel { + def id = _id def idInStore = Some(_id) } @@ -60,11 +60,10 @@ object MongoDBPolicy { final def fromOther(policy: PolicyModel, _id: String): MongoDBPolicy = { MongoDBPolicy( _id, - policy.id, policy.parentID, policy.validityTimespan, policy.resourceTypes, - policy.chargingBehaviorClasses, + policy.chargingBehaviors, policy.roleMapping ) } diff --git a/src/main/scala/gr/grnet/aquarium/util/Lock.scala b/src/main/scala/gr/grnet/aquarium/util/Lock.scala new file mode 100644 index 0000000..66235b9 --- /dev/null +++ b/src/main/scala/gr/grnet/aquarium/util/Lock.scala @@ -0,0 +1,53 @@ +/* + * 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.concurrent.locks.ReentrantLock + +/** + * A wrapper around [[java.util.concurrent.locks.ReentrantLock]] + * + * @author Christos KK Loverdos + */ + +final class Lock(isFair: Boolean = false) { + private[this] val lock = new ReentrantLock(isFair) + + def withLock[A](f: ⇒ A): A = { + lock.lock() + try f finally lock.unlock() + } +} diff --git a/src/test/resources/aquarium.properties b/src/test/resources/aquarium.properties index 0f22897..e86d736 100644 --- a/src/test/resources/aquarium.properties +++ b/src/test/resources/aquarium.properties @@ -59,7 +59,7 @@ mongodb.connection.pool.size=20 # Relative to AQUARIUM_HOME or an absolute path # DO NOT set this in production -#events.store.folder=../events-store +events.store.folder=../events-store # Store resource events to events.store.folder as well events.store.save.rc.events=false @@ -75,13 +75,9 @@ rest.service.class=gr.grnet.aquarium.service.FinagleRESTService rest.shutdown.timeout.millis=2000 # Store subsystem store.provider.class=gr.grnet.aquarium.store.mongodb.MongoDBStoreProvider -# Override the user store (if present, it will not be given by the store provider above) -#user.state.store.class=gr.grnet.aquarium.store.memory.MemStorede the event store (if present, it will not be given by the store provider above) -#resource.event.store.class= -# Override the user event store (if present, it will not be given by the store provider above) -#user.event.store.class= -# Override the user event store (if present, it will not be given by the store provider above) -#policy.store.class= + +# A time period in milliseconds for which we can tolerate stale parts regarding user state. +user.state.timestamp.threshold=1 # Administrative REST API authorization cookie admin.cookie=1 \ No newline at end of file diff --git a/src/test/resources/policy.json b/src/test/resources/policy.json new file mode 100644 index 0000000..e6bb9d7 --- /dev/null +++ b/src/test/resources/policy.json @@ -0,0 +1,61 @@ +{ + "id":"3F8A9777-8C12-4529-B8E4-256AD840BEF2", + + "validityTimespan":{ + "fromMillis":0, + "toMillis":9223372036854775807 + }, + + "resourceTypes":[ + { + "name":"bandwidth", + "unit":"MB/Hr", + "chargingBehavior":"gr.grnet.aquarium.charging.DiscreteChargingBehavior" + }, + { + "name":"vmtime", + "unit":"Hr", + "chargingBehavior":"gr.grnet.aquarium.charging.OnOffChargingBehavior" + }, + { + "name":"diskspace", + "unit":"MB/Hr", + "chargingBehavior":"gr.grnet.aquarium.charging.ContinuousChargingBehavior" + } + ], + + "chargingBehaviors":[ + "gr.grnet.aquarium.charging.DiscreteChargingBehavior", + "gr.grnet.aquarium.charging.OnOffChargingBehavior", + "gr.grnet.aquarium.charging.ContinuousChargingBehavior", + "gr.grnet.aquarium.charging.OnceChargingBehavior" + ], + + "roleMapping":{ + "default":{ + "perResource":{ + "bandwidth":{ + "priceOverrides":[ + { + "unitPrice":0.01 + } + ] + }, + "vmtime":{ + "priceOverrides":[ + { + "unitPrice":0.01 + } + ] + }, + "diskspace":{ + "priceOverrides":[ + { + "unitPrice":0.01 + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/DSLTimeFrameTest.scala b/src/test/scala/gr/grnet/aquarium/logic/test/DSLTimeFrameTest.scala index b8bf7a7..ab5df19 100644 --- a/src/test/scala/gr/grnet/aquarium/logic/test/DSLTimeFrameTest.scala +++ b/src/test/scala/gr/grnet/aquarium/logic/test/DSLTimeFrameTest.scala @@ -36,7 +36,6 @@ package gr.grnet.aquarium.logic.test import org.junit.Test import gr.grnet.aquarium.logic.accounting.dsl.Timeslot -import gr.grnet.aquarium.util.TestMethods import java.util.Date import scala._ import scala.Some diff --git a/src/test/scala/gr/grnet/aquarium/logic/test/TimeslotTest.scala b/src/test/scala/gr/grnet/aquarium/logic/test/TimeslotTest.scala index 9a259f9..a9d95dd 100644 --- a/src/test/scala/gr/grnet/aquarium/logic/test/TimeslotTest.scala +++ b/src/test/scala/gr/grnet/aquarium/logic/test/TimeslotTest.scala @@ -35,7 +35,6 @@ package gr.grnet.aquarium.logic.test -import gr.grnet.aquarium.util.TestMethods import org.junit.Assert._ import org.junit.{Test} import gr.grnet.aquarium.logic.accounting.dsl.Timeslot @@ -47,7 +46,7 @@ import gr.grnet.aquarium.util.date.MutableDateCalc * * @author Georgios Gousios */ -class TimeslotTest extends TestMethods { +class TimeslotTest /*extends TestMethods*/ { @Test def testOverlappingTimeslots = { diff --git a/src/test/scala/gr/grnet/aquarium/policy/StdPolicyTest.scala b/src/test/scala/gr/grnet/aquarium/policy/StdPolicyTest.scala new file mode 100644 index 0000000..f320cbf --- /dev/null +++ b/src/test/scala/gr/grnet/aquarium/policy/StdPolicyTest.scala @@ -0,0 +1,85 @@ +/* + * 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 org.junit.Test +import gr.grnet.aquarium.Timespan +import gr.grnet.aquarium.charging.{OnceChargingBehavior, ContinuousChargingBehavior, OnOffChargingBehavior, DiscreteChargingBehavior} +import gr.grnet.aquarium.converter.{StdConverters, PrettyJsonTextFormat} + +/** + * + * @author Christos KK Loverdos + */ + +class StdPolicyTest { + final lazy val policy = StdPolicy( + id = "policy-1", + parentID = None, + + validityTimespan = Timespan(0), + + resourceTypes = Set( + ResourceType("bandwidth", "MB/Hr", classOf[DiscreteChargingBehavior].getName), + ResourceType("vmtime", "Hr", classOf[OnOffChargingBehavior].getName), + ResourceType("diskspace", "MB/Hr", classOf[ContinuousChargingBehavior].getName) + ), + + chargingBehaviors = Set( + classOf[DiscreteChargingBehavior].getName, + classOf[OnOffChargingBehavior].getName, + classOf[ContinuousChargingBehavior].getName, + classOf[OnceChargingBehavior].getName + ), + + roleMapping = Map( + "default" -> FullPriceTable(Map( + "bandwidth" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil), + "vmtime" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil), + "diskspace" -> EffectivePriceTable(EffectiveUnitPrice(0.01, None) :: Nil) + )) + ) + ) + + @Test + def testJson(): Unit = { + val converters = StdConverters.AllConverters + val json = converters.convertEx[PrettyJsonTextFormat](policy) + val obj = converters.convertEx[StdPolicy](json) + + assert(policy == obj) + } +} diff --git a/src/test/scala/gr/grnet/aquarium/policy/test/EffectiveUnitPriceTest.scala b/src/test/scala/gr/grnet/aquarium/policy/test/EffectiveUnitPriceTest.scala deleted file mode 100644 index 063fb4c..0000000 --- a/src/test/scala/gr/grnet/aquarium/policy/test/EffectiveUnitPriceTest.scala +++ /dev/null @@ -1,156 +0,0 @@ -package gr.grnet.aquarium.policy.test - -import gr.grnet.aquarium.util.TestMethods -import org.junit.Test -import java.util -import gr.grnet.aquarium.logic.accounting.dsl.Timeslot -import gr.grnet.aquarium.policy.{EffectiveUnitPrice, CronSpec} - -/* - * 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. - */ - -/** - * Tests for the Timeslot class - * - * @author Prodromos Gerakios - */ -class EffectiveUnitPriceTest extends TestMethods { - - private type EFU = EffectiveUnitPrice - private type Intervals = List[Timeslot] - - private val printScreen = false - - private def noOverlap(i1:Intervals,i2:Intervals) = { - for { t1 <- i1 - t2 <- i2 - } assert(!t1.weakOverlaps(t2),"Intervals\n t1="+t1 + " \nand\n t2="+t2 + "\n overlap.") - } - - private def singleT(t:Timeslot,i1:Intervals,i2:Intervals) = { - var l = Timeslot.mergeOverlaps(i1++i2) - assert(l.size == 1) - assert(l.head == t) - - } - private def cronOK(cs:CronSpec,d:util.Date) = { - assert(cs.includes(d)) - } - - private def cronNotOK(cs:CronSpec,d:util.Date) = { - assert(!cs.includes(d)) - } - private def testEFU(start:Long,end:Long,v:Double,cronStart:String,cronEnd:String) : - (Intervals,Intervals) = { - var cronStart0 : CronSpec = null - var cronEnd0 : CronSpec = null - val opt = if (cronStart.isEmpty || cronEnd.isEmpty) None - else Some(({cronStart0=new CronSpec(cronStart);cronStart0}, - {cronEnd0=new CronSpec(cronEnd);cronEnd0})) - val ts=Timeslot(start,end) - if(printScreen) Console.err.println("Timeslot: " + ts) - val efu = new EffectiveUnitPrice(v,opt) - val (l1,l2) = efu.splitTimeslot(ts) - noOverlap(l1,l2) - singleT(ts,l1,l2) - if(cronStart0!=null && cronEnd0!=null){ - for { - t <- l1 - } { - cronOK(cronStart0,t.from) - cronOK(cronEnd0,t.to) - } - for { - t <- l2 - } { - cronNotOK(cronStart0,t.from) - cronNotOK(cronEnd0,t.to) - } - } - (l1,l2) - } - - private def print(i:Intervals){ - if(printScreen) { - Console.err.println("BEGIN INTERVAL") - for { ii <-i } Console.err.println(ii) - Console.err.println("END INTERVAL") - } - } - - - @Test - def splitTest1 = { - testEFU( - 1321621969000L, //Fri Nov 18 15:12:49 +0200 2011 - 1324214719000L, //Sun Dec 18 15:25:19 +0200 2011 - 5.0, - "33 12 * * *", - "33 13 * * *" - ) - val (l2_a,l2_b) = testEFU( - 1321621969000L, //Fri Nov 18 15:12:49 +0200 2011 - 1321795519000L, //Sun Nov 20 15:25:19 +0200 2011 - 8.0, - "15 12 * * *", - "33 13 * * *" - ) - assert(l2_a.size == 2) - print(l2_a) - - val (l3_a,l3_b) = testEFU( - 1321621969000L, //Fri Nov 18 15:12:49 +0200 2011 - 1321795519000L, //Sun Nov 20 15:25:19 +0200 2011 - 10.0, - "33 12 * * *", - "33 13 * * *" - ) - print(l3_a) - assert(l3_a.size == 2) - - val (l4_a,l4_b) = testEFU( - 1321621969000L, //Fri Nov 18 15:12:49 +0200 2011 - 1321795519000L, //Sun Nov 20 15:25:19 +0200 2011 - 15.0, - "33 12 * * *", - "33 13 * * *" - ) - print(l4_a) - assert(l4_a.size == 2) - - () - } - -} diff --git a/src/test/scala/gr/grnet/aquarium/user/UserStateComputationsTest.scala b/src/test/scala/gr/grnet/aquarium/user/UserStateComputationsTest.scala index 7fe30b2..24f0dd0 100644 --- a/src/test/scala/gr/grnet/aquarium/user/UserStateComputationsTest.scala +++ b/src/test/scala/gr/grnet/aquarium/user/UserStateComputationsTest.scala @@ -36,24 +36,20 @@ package gr.grnet.aquarium.user import gr.grnet.aquarium.store.memory.MemStoreProvider -import gr.grnet.aquarium.logic.accounting.dsl._ 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.{ExecutableChargingBehaviorAlgorithm, CostPolicyAlgorithmCompiler} -import gr.grnet.aquarium.{Timespan, Aquarium, ResourceLocator, AquariumBuilder, AquariumException} +import gr.grnet.aquarium.{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.computation.state.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 /** @@ -76,14 +72,15 @@ class UserStateComputationsTest extends Loggable { parentID = None, validityTimespan = Timespan(0), resourceTypes = Set( - ResourceType("bandwidth", "MB/Hr", DiscreteChargingBehavior), - ResourceType("vmtime", "Hr", OnOffChargingBehavior), - ResourceType("diskspace", "MB/Hr", ContinuousChargingBehavior) + ResourceType("bandwidth", "MB/Hr", classOf[DiscreteChargingBehavior].getName), + ResourceType("vmtime", "Hr", classOf[OnOffChargingBehavior].getName), + ResourceType("diskspace", "MB/Hr", classOf[ContinuousChargingBehavior].getName) ), - chargingBehaviorClasses = Set( - DiscreteChargingBehavior.getClass.getName, - OnOffChargingBehavior.getClass.getName, - ContinuousChargingBehavior.getClass.getName + chargingBehaviors = Set( + classOf[DiscreteChargingBehavior].getName, + classOf[OnOffChargingBehavior].getName, + classOf[ContinuousChargingBehavior].getName, + classOf[OnceChargingBehavior].getName ), roleMapping = Map( "default" -> FullPriceTable(Map( @@ -123,7 +120,7 @@ class UserStateComputationsTest extends Loggable { def apply(vars: Map[ChargingInput, Any]): Double = { vars.apply(ChargingBehaviorNameInput) match { - case ChargingBehaviorNames.continuous ⇒ + case ChargingBehaviorAliases.continuous ⇒ val unitPrice = vars(UnitPriceInput).asInstanceOf[Double] val oldTotalAmount = vars(OldTotalAmountInput).asInstanceOf[Double] val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double] @@ -132,7 +129,7 @@ class UserStateComputationsTest extends Loggable { creditsForContinuous(timeDelta, oldTotalAmount) - case ChargingBehaviorNames.discrete ⇒ + case ChargingBehaviorAliases.discrete ⇒ val unitPrice = vars(UnitPriceInput).asInstanceOf[Double] val currentValue = vars(CurrentValueInput).asInstanceOf[Double] @@ -140,7 +137,7 @@ class UserStateComputationsTest extends Loggable { creditsForDiscrete(currentValue) - case ChargingBehaviorNames.onoff ⇒ + case ChargingBehaviorAliases.onoff ⇒ val unitPrice = vars(UnitPriceInput).asInstanceOf[Double] val timeDelta = vars(TimeDeltaInput).asInstanceOf[Double] @@ -148,7 +145,7 @@ class UserStateComputationsTest extends Loggable { creditsForOnOff(timeDelta) - case ChargingBehaviorNames.once ⇒ + case ChargingBehaviorAliases.once ⇒ val currentValue = vars(CurrentValueInput).asInstanceOf[Double] currentValue @@ -159,10 +156,10 @@ class UserStateComputationsTest extends Loggable { override def toString = "DefaultAlgorithm(%s)".format( Map( - ChargingBehaviorNames.continuous -> "hrs(timeDelta) * oldTotalAmount * %s".format(ContinuousUnitPrice), - ChargingBehaviorNames.discrete -> "currentValue * %s".format(DiscreteUnitPrice), - ChargingBehaviorNames.onoff -> "hrs(timeDelta) * %s".format(OnOffUnitPrice), - ChargingBehaviorNames.once -> "currentValue")) + ChargingBehaviorAliases.continuous -> "hrs(timeDelta) * oldTotalAmount * %s".format(ContinuousUnitPrice), + ChargingBehaviorAliases.discrete -> "currentValue * %s".format(DiscreteUnitPrice), + ChargingBehaviorAliases.onoff -> "hrs(timeDelta) * %s".format(OnOffUnitPrice), + ChargingBehaviorAliases.once -> "currentValue")) } val DefaultCompiler = new CostPolicyAlgorithmCompiler { -- 1.7.10.4