{
- "id":"750E6309-AB60-41B4-8D4B-9FFEA6EF843C",
-
+ "id":"policy-1",
"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.VMChargingBehavior"
],
"chargingBehaviors":[
- "gr.grnet.aquarium.charging.DiscreteChargingBehavior",
"gr.grnet.aquarium.charging.VMChargingBehavior",
"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
- }
- ]
- }
+ "vmtime": { "priceOverrides":[ { "unitPrice":0.01 } ] },
+ "diskspace": { "priceOverrides":[ { "unitPrice":0.01 } ] }
}
}
}
-import gr.grnet.aquarium.charging.{OnceChargingBehavior, ContinuousChargingBehavior, VMChargingBehavior, DiscreteChargingBehavior}
-import gr.grnet.aquarium.policy.{IsSelectorMap, IsEffectivePriceTable, EffectiveUnitPrice, EffectivePriceTable, FullPriceTable, ResourceType, StdPolicy}
+import gr.grnet.aquarium.charging.VMChargingBehavior.Selectors.Power
+import gr.grnet.aquarium.charging.{OnceChargingBehavior, ContinuousChargingBehavior, VMChargingBehavior}
+import gr.grnet.aquarium.policy.FullPriceTable._
+import gr.grnet.aquarium.policy.{EffectiveUnitPrice, EffectivePriceTable, FullPriceTable, ResourceType, StdPolicy}
import gr.grnet.aquarium.Timespan
+import gr.grnet.aquarium.util.nameOfClass
// Definition of our standard policy in plain Scala
validityTimespan = Timespan(0),
resourceTypes = Set(
- ResourceType("bandwidth", "MB/Hr", classOf[DiscreteChargingBehavior].getName),
- ResourceType("vmtime", "Hr", classOf[VMChargingBehavior].getName),
- ResourceType("diskspace", "MB/Hr", classOf[ContinuousChargingBehavior].getName)
+ ResourceType("vmtime", "Hr", nameOfClass[VMChargingBehavior]),
+ ResourceType("diskspace", "MB/Hr", nameOfClass[ContinuousChargingBehavior])
),
chargingBehaviors = Set(
- classOf[DiscreteChargingBehavior].getName,
- classOf[VMChargingBehavior].getName,
- classOf[ContinuousChargingBehavior].getName,
- classOf[OnceChargingBehavior].getName
+ nameOfClass[VMChargingBehavior],
+ nameOfClass[ContinuousChargingBehavior],
+ nameOfClass[OnceChargingBehavior]
),
roleMapping = Map(
"default" -> FullPriceTable(Map(
- "bandwidth" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)),
- "diskspace" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)),
- "vmtime" -> IsSelector(Map(
- VMChargingBehavior.Selectors._1.powerOn ->
- IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.02) :: Nil)),
- VMChargingBehavior.Selectors._1.powerOff ->
- IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)) // powerOff is cheaper!
- ))
+ "diskspace" -> Map(
+ DefaultSelectorKey -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)
+ ),
+ "vmtime" -> Map(
+ Power.powerOn -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil),
+ Power.powerOff -> EffectivePriceTable(EffectiveUnitPrice(0.001) :: Nil) // cheaper when the VM is OFF
+ )
))
)
)
\ No newline at end of file
import gr.grnet.aquarium.event.model.resource.ResourceEventModel
import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
import scala.collection.mutable
+import VMChargingBehavior.Selectors.Power
+
/**
- * 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.
+ * The new [[gr.grnet.aquarium.charging.ChargingBehavior]] for VMs usage.
*
* @author Christos KK Loverdos <loverdos@gmail.com>
*/
extends ChargingBehavior(
ChargingBehaviorAliases.vmtime,
Set(ChargingBehaviorNameInput, UnitPriceInput, TimeDeltaInput),
- List(List(VMChargingBehavior.Selectors._1.powerOn, VMChargingBehavior.Selectors._1.powerOff))) {
+ List(List(Power.powerOn, Power.powerOff))) {
protected def computeSelectorPath(
chargingData: mutable.Map[String, Any],
newAccumulatingAmount: Double
): List[String] = {
// FIXME
- List(VMChargingBehavior.Selectors._1.powerOn) // compute prices for power-on state
+ List(Power.powerOn) // compute prices for power-on state
}
/**
*
object VMChargingBehavior {
object Selectors {
- object _1 {
+ object Power {
// When the VM is powered on
final val powerOn = "powerOn"
// When the VM is powered off
import gr.grnet.aquarium.util.{makeString, UTF_8_Charset}
import java.nio.charset.Charset
+import gr.grnet.aquarium.policy.PolicyModel
/**
* Provides conversion methods from and to JSON.
/**
* The application-wide JSON formats used from the underlying lift-json library.
*/
- implicit final val Formats = (DefaultFormats ++ JodaTimeSerializers.all)
-// implicit final val Formats = (DefaultFormats.withHints(FullTypeHints(List(classOf[AnyRef]))) ++ JodaTimeSerializers.all)
+// implicit final val Formats = (DefaultFormats ++ JodaTimeSerializers.all)
+ implicit final val Formats = (DefaultFormats.withHints(FullTypeHints(List(classOf[AnyRef]))) ++ JodaTimeSerializers.all)
// Serialization.formats(FullTypeHints(List(classOf[AnyRef])))
+// final val PolicyModelSerializer: Serializer[PolicyModel] = new Serializer[PolicyModel] {
+// def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, _root_.net.liftweb.json.JValue), PolicyModel] = {
+// case (tpe @ TypeInfo(_, _), jValue) ⇒
+// println("!! tpe = " + tpe)
+// println("!! jValue = " + jValue)
+// Extraction.extract(jValue, tpe)(FullFormats).asInstanceOf[PolicyModel]
+// }
+//
+// def serialize(implicit format: Formats): PartialFunction[Any, _root_.net.liftweb.json.JValue] = {
+// case x: PolicyModel ⇒
+// println("GOT a policymodel")
+// Extraction.decompose(x)(FullFormats)
+// }
+// }
/**
* Converts a value to JSON AST (Abstract Syntax Tree) by acting a bit intelligently, depending on the actual type
import com.mongodb.util.JSON
import com.mongodb.DBObject
import xml.NodeSeq
-import net.liftweb.json.Xml
+import net.liftweb.json.{Printer, JsonAST, Extraction, Xml}
+import gr.grnet.aquarium.policy.PolicyModel
/**
private[this] final lazy val builder: ConvertersBuilder = {
val builder: ConvertersBuilder = new StdConvertersBuilder().registerDefaultConversions()
+ // PolicyModel ⇒ JValue
+// builder.registerConverter(PolicyModelToJValueConverter)
+
+ // PolicyModel ⇒ PrettyJsonTextFormat
+// builder.registerConverter(PolicyModelToPrettyJsonTextFormatConverter)
+
+ // PolicyModel ⇒ CompactJsonTextFormat
+// builder.registerConverter(PolicyModelToCompactJsonTextFormatConverter)
+
// Any ⇒ JValue
builder.registerConverter(AnyToJValueConverter)
// Any ⇒ CompactJsonTextFormat
builder.registerConverter(AnyToCompactJsonTextConverter)
+ // JsonTextFormat ⇒ PolicyModel
+// builder.registerConverter(JsonTextToPolicyModelConverter)
+
// JsonTextFormat ⇒ AnyRef
builder.registerConverter(JsonTextToObjectConverter)
builder
}
+// object PolicyModelToJValueConverter
+// extends NonStrictSourceConverterSkeleton[PolicyModel, JValue] {
+// protected def convertEx_(sourceValue: PolicyModel): JValue = {
+// Extraction.decompose(sourceValue)(JsonConversions.FullFormats)
+// }
+// }
+
+// object PolicyModelToPrettyJsonTextFormatConverter
+// extends NonStrictSourceConverterSkeleton[PolicyModel, PrettyJsonTextFormat] {
+// protected def convertEx_(sourceValue: PolicyModel): PrettyJsonTextFormat = {
+// val jValue = Extraction.decompose(sourceValue)(JsonConversions.FullFormats)
+// val jDoc = JsonAST.render(jValue)
+// PrettyJsonTextFormat(Printer.pretty(jDoc))
+// }
+// }
+
+// object PolicyModelToCompactJsonTextFormatConverter
+// extends NonStrictSourceConverterSkeleton[PolicyModel, CompactJsonTextFormat] {
+// protected def convertEx_(sourceValue: PolicyModel): CompactJsonTextFormat = {
+// val jValue = Extraction.decompose(sourceValue)(JsonConversions.FullFormats)
+// val jDoc = JsonAST.render(jValue)
+// CompactJsonTextFormat(Printer.compact(jDoc))
+// }
+// }
+
object ByteArrayToJsonTextConverter extends StrictSourceConverterSkeleton[Array[Byte], JsonTextFormat] {
@throws(classOf[ConverterException])
final protected def convertEx_(sourceValue: Array[Byte]) = {
}
}
+// object JsonTextToPolicyModelConverter extends Converter {
+// def isStrictSource = false
+//
+// def canConvertType[S: Type, T: Type] = {
+// erasureOf[JsonTextFormat].isAssignableFrom(erasureOf[S])
+// }
+//
+// @throws(classOf[ConverterException])
+// def convertEx[T: Type](sourceValue: Any) = {
+// // Generic deserializer from json string to a business logic model
+// JsonConversions.jsonToObject[T](sourceValue.asInstanceOf[JsonTextFormat].value)(manifest[T], JsonConversions.FullFormats)
+// }
+// }
+
object JsonSupportToDBObjectConverter extends NonStrictSourceConverterSkeleton[JsonSupport, DBObject] {
@throws(classOf[ConverterException])
final protected def convertEx_(sourceValue: JsonSupport) = {
* @author Christos KK Loverdos <loverdos@gmail.com>
*/
-case class FullPriceTable(perResource: Map[String/*Resource*/, SelectorMapOrEffectivePriceTable]) {
- def effectivePriceTableOfSelector(selectorPath: List[String], resource: String): EffectivePriceTable = {
+case class FullPriceTable(
+ perResource: Map[String/*Resource*/,
+ Map[String/*Per-ChargingBehavior Key, "default" is the default*/, Any]]
+) {
+
+ def effectivePriceTableOfSelectorForResource(
+ selectorPath: List[String],
+ resource: String
+ ): EffectivePriceTable = {
+
@tailrec
def find(
selectorPath: List[String],
- soeOfResource: SelectorMapOrEffectivePriceTable
+ selectorData: Any
): EffectivePriceTable = {
selectorPath match {
case Nil ⇒
- if(soeOfResource.isSelectorMap) {
- throw new AquariumInternalError("Expecting an %s but got a selector", shortNameOfType[EffectivePriceTable])
+ // End of selector path. This means that the data must be an EffectivePriceTable
+ selectorData match {
+ case ept: EffectivePriceTable ⇒
+ ept
+
+ case _ ⇒
+ // TODO more informative error message (include selector path, resource?)
+ throw new AquariumInternalError("Got %s instead of an %s", selectorData, shortNameOfType[EffectivePriceTable])
}
- soeOfResource.effectivePriceTable
case key :: tailSelectorPath ⇒
- if(!soeOfResource.isSelectorMap) {
- throw new AquariumInternalError("Expecting a selector but got an %s", shortNameOfType[EffectivePriceTable])
- }
-
- val selctorMap = soeOfResource.selectorMap
- val selectedOpt = selctorMap.get(key)
- if(selectedOpt.isEmpty) {
- throw new AquariumInternalError("Could not find selector '%s'", key)
+ // Intermediate path. This means we have another round of Map[String, Any]
+ selectorData match {
+ case selectorMap: Map[_, _] ⇒
+ selectorMap.asInstanceOf[Map[String, _]].get(key) match {
+ case None ⇒
+ throw new AquariumInternalError("Did not find value for selector %s", key)
+
+ case Some(nextSelectorData) ⇒
+ find(tailSelectorPath, nextSelectorData)
+ }
}
-
- find(tailSelectorPath, selectedOpt.get)
}
}
- val soeOfResourceOpt = perResource.get(resource)
- if(soeOfResourceOpt.isEmpty) {
+ val selectorDataOpt = perResource.get(resource)
+ if(selectorDataOpt.isEmpty) {
throw new AquariumInternalError("Unknown resource type '%s'", resource)
}
+ val selectorData = selectorDataOpt.get
- find(selectorPath, soeOfResourceOpt.get)
+ find(selectorPath, selectorData)
}
}
-sealed trait SelectorMapOrEffectivePriceTable {
- def isSelectorMap: Boolean
-
- def selectorMap: Map[String, SelectorMapOrEffectivePriceTable]
-
- def effectivePriceTable: EffectivePriceTable
-}
-
-case class IsSelectorMap(selectorMap: Map[String, SelectorMapOrEffectivePriceTable]) extends SelectorMapOrEffectivePriceTable {
- def isSelectorMap = true
-
- def effectivePriceTable =
- throw new AquariumInternalError("Accessed effectivePriceTable of %s", shortNameOfType[IsSelectorMap])
-}
-
-case class IsEffectivePriceTable(effectivePriceTable: EffectivePriceTable) extends SelectorMapOrEffectivePriceTable {
- def isSelectorMap = false
-
- def selectorMap =
- throw new AquariumInternalError("Accessed selector of %s", shortNameOfType[IsEffectivePriceTable])
+object FullPriceTable {
+ final val DefaultSelectorKey = "default"
}
\ No newline at end of file
import gr.grnet.aquarium.{AquariumInternalError, Timespan}
import gr.grnet.aquarium.util.json.JsonSupport
import gr.grnet.aquarium.charging.ChargingBehavior
+import gr.grnet.aquarium.converter.{JsonTextFormat, StdConverters}
/**
* A policy is the fundamental business-related configuration of Aquarium.
}
final object Names extends NamesT
+
+ def fromJsonString(json: String): PolicyModel = {
+ StdConverters.AllConverters.convertEx[StdPolicy](JsonTextFormat(json))
+ }
}
fullPriceTable
}
- fullPriceTable.effectivePriceTableOfSelector(selectorPath, resource)
+ fullPriceTable.effectivePriceTableOfSelectorForResource(selectorPath, resource)
}
}
}
@inline
- def StartStopErrorHandler[S](logger: Logger,
- message: String,
- onException: ⇒ Unit = {}): PartialFunction[Throwable, Unit] = {
+ def StartStopErrorHandler[S](
+ logger: Logger,
+ message: String,
+ onException: ⇒ Unit = {}
+ ): PartialFunction[Throwable, Unit] = {
case e: Throwable ⇒
safeUnit(onException)
afterLastIndexOf(".", manifest[C].toString)
}
+ def nameOfClass[C: ClassManifest] = classManifest[C].erasure.getName
+
/**
* Compute the class name excluding any leading packages and any `$` prefixes.
*
"[%s] %s".format(obj.getClass, obj)
}
- /**
- * This basically turns an [[scala.Option]] into a [[com.ckkloverdos.maybe.Maybe]] when asking a
- * [[scala.collection.Map]] for a key.
- *
- * @param map The input map.
- * @param key The key we are interested in.
- * @tparam A The type of keys.
- * @tparam B The type of values.
- *
- * @return A [[com.ckkloverdos.maybe.Just]] if a value was found, a
- * [[com.ckkloverdos.maybe.NoVal]] if nothing was found and a
- * [[com.ckkloverdos.maybe.Failed]] if some error happened.
- */
- @inline
- def findFromMapAsMaybe[A, B <: AnyRef](map: scala.collection.Map[A, B], key: A): Maybe[B] = Maybe {
- map.get(key) match {
- case Some(value) ⇒
- value
- case None ⇒
- null.asInstanceOf[B]
- }
- }
-
- @inline
- def findAndRemoveFromMap[A, B <: AnyRef](map: scala.collection.mutable.Map[A, B], key: A): Option[B] = {
- map.remove(key)
- }
-
// Dear scalac. Optimize this.
def nspaces(n: Int): String = {
("" /: (1 to n)) ((string, _) => string + " ")
import org.junit.Test
import gr.grnet.aquarium.Timespan
import gr.grnet.aquarium.charging.{OnceChargingBehavior, ContinuousChargingBehavior, VMChargingBehavior}
-import gr.grnet.aquarium.converter.{StdConverters, PrettyJsonTextFormat}
+import gr.grnet.aquarium.charging.VMChargingBehavior.Selectors.Power
+import gr.grnet.aquarium.util.nameOfClass
+import FullPriceTable.DefaultSelectorKey
/**
*
validityTimespan = Timespan(0),
resourceTypes = Set(
- ResourceType("diskspace", "MB/Hr", classOf[ContinuousChargingBehavior].getName),
- ResourceType("vmtime", "Hr", classOf[VMChargingBehavior].getName)
+ ResourceType("diskspace", "MB/Hr", nameOfClass[ContinuousChargingBehavior]),
+ ResourceType("vmtime", "Hr", nameOfClass[VMChargingBehavior])
),
chargingBehaviors = Set(
- classOf[VMChargingBehavior].getName,
- classOf[ContinuousChargingBehavior].getName,
- classOf[OnceChargingBehavior].getName
+ nameOfClass[VMChargingBehavior],
+ nameOfClass[ContinuousChargingBehavior],
+ nameOfClass[OnceChargingBehavior]
),
roleMapping = Map(
"default" -> FullPriceTable(Map(
- "bandwidth" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)),
- "diskspace" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)),
- "vmtime" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil))
+ "diskspace" -> Map(
+ DefaultSelectorKey -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)
+ ),
+ "vmtime" -> Map(
+ Power.powerOn -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil),
+ Power.powerOff -> EffectivePriceTable(EffectiveUnitPrice(0.001) :: Nil) // cheaper when the VM is OFF
+ )
))
)
)
@Test
def testJson(): Unit = {
- val converters = StdConverters.AllConverters
- val json = converters.convertEx[PrettyJsonTextFormat](policy)
- val obj = converters.convertEx[StdPolicy](json)
+ val json = policy.toJsonString
+ println(json)
+
+ val obj = PolicyModel.fromJsonString(json)
assert(policy == obj)
}
import gr.grnet.aquarium.util.date.MutableDateCalc
import gr.grnet.aquarium.computation.BillingMonthInfo
import gr.grnet.aquarium.charging._
-import gr.grnet.aquarium.policy.{IsEffectivePriceTable, PolicyDefinedFullPriceTableRef, StdUserAgreement, EffectiveUnitPrice, EffectivePriceTable, FullPriceTable, ResourceType, StdPolicy, PolicyModel}
-import gr.grnet.aquarium.Timespan
-import gr.grnet.aquarium.charging.state.UserStateBootstrap
+import gr.grnet.aquarium.policy.{PolicyDefinedFullPriceTableRef, FullPriceTable, PolicyModel}
import gr.grnet.aquarium.charging.reason.{NoSpecificChargingReason, MonthlyBillChargingReason}
import gr.grnet.aquarium.charging.state.WorkingUserState
+import gr.grnet.aquarium.policy.FullPriceTable._
+import gr.grnet.aquarium.Timespan
+import gr.grnet.aquarium.simulation.AquariumSim
+import scala.Some
+import gr.grnet.aquarium.policy.EffectiveUnitPrice
+import gr.grnet.aquarium.policy.ResourceType
+import gr.grnet.aquarium.policy.StdUserAgreement
+import gr.grnet.aquarium.charging.state.UserStateBootstrap
+import gr.grnet.aquarium.policy.EffectivePriceTable
+import gr.grnet.aquarium.policy.StdPolicy
+import gr.grnet.aquarium.simulation.ClientSim
/**
),
roleMapping = Map(
"default" -> FullPriceTable(Map(
- "bandwidth" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(BandwidthUnitPrice) :: Nil)),
- "diskspace" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(DiskspaceUnitPrice) :: Nil)),
- "vmtime" -> IsEffectivePriceTable(EffectivePriceTable(EffectiveUnitPrice(VMTimeUnitPrice) :: Nil))
+ "bandwidth" -> Map(DefaultSelectorKey -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)),
+ "diskspace" -> Map(DefaultSelectorKey -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil)),
+ "vmtime" -> Map(DefaultSelectorKey -> EffectivePriceTable(EffectiveUnitPrice(0.01) :: Nil))
))
)
)