Manually revert to ddd366d
authorChristos KK Loverdos <loverdos@gmail.com>
Fri, 13 Jul 2012 09:16:56 +0000 (12:16 +0300)
committerChristos KK Loverdos <loverdos@gmail.com>
Fri, 13 Jul 2012 09:16:56 +0000 (12:16 +0300)
43 files changed:
src/main/resources/aquarium.properties
src/main/resources/policy.json [new file with mode: 0644]
src/main/resources/policy.scala
src/main/scala/gr/grnet/aquarium/Aquarium.scala
src/main/scala/gr/grnet/aquarium/AquariumBuilder.scala
src/main/scala/gr/grnet/aquarium/Main.scala
src/main/scala/gr/grnet/aquarium/ResourceLocator.scala
src/main/scala/gr/grnet/aquarium/charging/ChargingBehavior.scala
src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorAliases.scala [moved from src/main/scala/gr/grnet/aquarium/charging/ChargingBehaviorNames.scala with 98% similarity]
src/main/scala/gr/grnet/aquarium/charging/ContinuousChargingBehavior.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/charging/DiscreteChargingBehavior.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehavior.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/charging/OnOffChargingBehaviorValues.scala [moved from src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceStateNames.scala with 90% similarity]
src/main/scala/gr/grnet/aquarium/charging/OnOffPolicyResourceState.scala
src/main/scala/gr/grnet/aquarium/charging/OnceChargingBehavior.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/computation/TimeslotComputations.scala
src/main/scala/gr/grnet/aquarium/computation/UserStateComputations.scala
src/main/scala/gr/grnet/aquarium/computation/state/UserStateWorker.scala
src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm.scala [moved from src/main/scala/gr/grnet/aquarium/logic/accounting/algorithm/SimpleExecutableChargingBehaviorAlgorithm$.scala with 82% similarity]
src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/Timeslot.scala
src/main/scala/gr/grnet/aquarium/policy/EffectiveUnitPrice.scala
src/main/scala/gr/grnet/aquarium/policy/PolicyHistory.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/policy/PolicyModel.scala
src/main/scala/gr/grnet/aquarium/policy/ResourceType.scala
src/main/scala/gr/grnet/aquarium/policy/StdPolicy.scala
src/main/scala/gr/grnet/aquarium/service/AkkaService.scala
src/main/scala/gr/grnet/aquarium/service/FinagleRESTService.scala
src/main/scala/gr/grnet/aquarium/service/RESTPaths.scala
src/main/scala/gr/grnet/aquarium/service/StoreWatcherService.scala
src/main/scala/gr/grnet/aquarium/simulation/ResourceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthResourceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceResourceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeResourceSim.scala
src/main/scala/gr/grnet/aquarium/store/memory/MemStoreProvider.scala
src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBPolicy.scala
src/main/scala/gr/grnet/aquarium/util/Lock.scala [new file with mode: 0644]
src/test/resources/aquarium.properties
src/test/resources/policy.json [new file with mode: 0644]
src/test/scala/gr/grnet/aquarium/logic/test/DSLTimeFrameTest.scala
src/test/scala/gr/grnet/aquarium/logic/test/TimeslotTest.scala
src/test/scala/gr/grnet/aquarium/policy/StdPolicyTest.scala [new file with mode: 0644]
src/test/scala/gr/grnet/aquarium/policy/test/EffectiveUnitPriceTest.scala [deleted file]
src/test/scala/gr/grnet/aquarium/user/UserStateComputationsTest.scala

index dfaadec..325d4a9 100644 (file)
@@ -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 (file)
index 0000000..179e153
--- /dev/null
@@ -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
index 68176fc..0657131 100644 (file)
@@ -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
index a31281e..a71c08e 100644 (file)
@@ -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
index e1ec73c..2d09905 100644 (file)
@@ -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
index 65dccac..4500218 100644 (file)
@@ -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
index 4f4bb44..3bd1398 100644 (file)
 
 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 <loverdos@gmail.com>
  */
 
@@ -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)
       }
     }
   }
index eb1c979..4c252e1 100644 (file)
@@ -45,7 +45,7 @@ import gr.grnet.aquarium.{AquariumInternalError, AquariumException}
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-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("<null> 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))
-  }
-}
@@ -40,7 +40,7 @@ package gr.grnet.aquarium.charging
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-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 (file)
index 0000000..473d88d
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+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 (file)
index 0000000..178237f
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+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 (file)
index 0000000..e84e269
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+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
+}
@@ -40,7 +40,11 @@ package gr.grnet.aquarium.charging
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-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
 }
+
index 4e3d3a1..2ae9a96 100644 (file)
@@ -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 (file)
index 0000000..1a1213d
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+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
+}
index d5cabe1..09714b3 100644 (file)
@@ -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
index b2e8677..6d7cb76 100644 (file)
@@ -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("")
index bb0692f..40c2e71 100644 (file)
@@ -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)) {
 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"))
 }
index c81f867..8168faf 100644 (file)
@@ -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,
index 37fb7ae..b0f7ac7 100644 (file)
@@ -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 (file)
index 0000000..e15a901
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+
+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
+    }
+  }
+}
index 7e6fa50..f5e9eb7 100644 (file)
@@ -49,14 +49,23 @@ import gr.grnet.aquarium.charging.ChargingBehavior
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-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.
index d01da5e..7545903 100644 (file)
 
 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 <loverdos@gmail.com>
  */
-case class ResourceType(name: String, unit: String, chargingBehavior: ChargingBehavior)
+case class ResourceType(name: String, unit: String, chargingBehavior: String)
index ce3239a..0b0667b 100644 (file)
@@ -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 {
 
index 1b86d54..bcd574f 100644 (file)
@@ -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
index 2602e0f..553e96f 100644 (file)
@@ -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 = {
index 00e9b9f..3717583 100644 (file)
@@ -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
 
index 271a409..a5bc21f 100644 (file)
@@ -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,
index f9bf56d..abf2f34 100644 (file)
@@ -46,7 +46,7 @@ import gr.grnet.aquarium.charging.ChargingBehavior
  * @author Christos KK Loverdos <loverdos@gmail.com>
  */
 
-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)
   }
 
 }
index c722649..117af66 100644 (file)
@@ -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)
index 3abe3e8..97d4813 100644 (file)
@@ -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) =
index d15e18b..a65537b 100644 (file)
@@ -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) =
index f58fe3d..e513606 100644 (file)
@@ -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
index bf7150b..576ef86 100644 (file)
@@ -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 (file)
index 0000000..66235b9
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+
+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()
+  }
+}
index 0f22897..e86d736 100644 (file)
@@ -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 (file)
index 0000000..e6bb9d7
--- /dev/null
@@ -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
index b8bf7a7..ab5df19 100644 (file)
@@ -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
index 9a259f9..a9d95dd 100644 (file)
@@ -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 <gousiosg@gmail.com>
  */
-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 (file)
index 0000000..f320cbf
--- /dev/null
@@ -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 <loverdos@gmail.com>
+ */
+
+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 (file)
index 063fb4c..0000000
+++ /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 <pgerakios@grnet.gr>
- */
-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)
-
-    ()
-  }
-
-}
index 7fe30b2..24f0dd0 100644 (file)
 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 {