Merge branch 'master'
authorChristos KK Loverdos <loverdos@gmail.com>
Wed, 19 Sep 2012 07:55:11 +0000 (10:55 +0300)
committerChristos KK Loverdos <loverdos@gmail.com>
Wed, 19 Sep 2012 07:55:35 +0000 (10:55 +0300)
src/main/resources/policy.json
src/main/scala/gr/grnet/aquarium/actor/service/user/UserActor.scala
src/main/scala/gr/grnet/aquarium/charging/bill/BillEntry.scala
src/test/resources/policy.json
src/test/scala/gr/grnet/aquarium/BillTest.scala

index 4da3cf1..f588dc9 100644 (file)
@@ -8,7 +8,7 @@
   "resourceTypes":[
     {
       "name":"diskspace",
-      "unit":"MB/Hr",
+      "unit":"MB-Hr",
       "chargingBehaviorClass":"gr.grnet.aquarium.charging.ContinuousChargingBehavior"
     },
     {
index 0c1cbb6..7d339a4 100644 (file)
@@ -58,6 +58,7 @@ import gr.grnet.aquarium.message.avro.{ModelFactory, MessageFactory, MessageHelp
 import gr.grnet.aquarium.service.event.BalanceEvent
 import gr.grnet.aquarium.util.date.TimeHelpers
 import gr.grnet.aquarium.util.{LogHelpers, shortClassNameOf}
+import gr.grnet.aquarium.policy.{ResourceType, PolicyModel}
 
 /**
  *
@@ -385,8 +386,15 @@ class UserActor extends ReflectiveRoleableActor {
   def onGetUserBillRequest(event: GetUserBillRequest): Unit = {
     try{
       val timeslot = event.timeslot
+      val resourceTypes = aquarium.policyStore.
+                          loadSortedPolicyModelsWithin(timeslot.from.getTime,
+                                                       timeslot.to.getTime).
+                          values.headOption match {
+          case None => Map[String,ResourceType]()
+          case Some(policy:PolicyModel) => policy.resourceTypesMap
+      }
       val state= if(haveUserState) Some(this._userState.msg) else None
-      val billEntry = AbstractBillEntry.fromWorkingUserState(timeslot,this._userID,state)
+      val billEntry = AbstractBillEntry.fromWorkingUserState(timeslot,this._userID,state,resourceTypes)
       val billData = GetUserBillResponseData(this._userID,billEntry)
       sender ! GetUserBillResponse(Right(billData))
     } catch {
index 461c226..dfe2110 100644 (file)
@@ -48,6 +48,7 @@ import java.io.File
 import java.util.concurrent.atomic.AtomicLong
 import scala.collection.immutable.TreeMap
 import scala.collection.mutable.ListBuffer
+import gr.grnet.aquarium.policy.ResourceType
 
 
 /*
@@ -70,18 +71,22 @@ class EventEntry(val eventType : String,
 
 
 case class ResourceEntry(val resourceName : String,
-                         val resourceType : String,
-                         val unitName : String,
+                         //val resourceType : String,
+                         //val unitName : String,
                          val totalCredits : String,
                          val totalElapsedTime : String,
                          val totalUnits : String,
                          val details : List[EventEntry])
-extends JsonSupport {}
+extends JsonSupport {
+   var unitName = "EMPTY_UNIT_NAME"
+   var resourceType = "EMPTY_RESOURCE_TYPE"
+}
 
 case class ServiceEntry(val serviceName: String,
                         val totalCredits : String,
                         val totalElapsedTime : String,
                         val totalUnits:String,
+                        val unitName:String,
                         val details: List[ResourceEntry]
                        )
 extends JsonSupport {}
@@ -182,8 +187,11 @@ object AbstractBillEntry {
         }
       }
     //Console.err.println("TOTAL resource event credits: " + credits)
-    new ResourceEntry(rcName,rcType,rcUnitName,credits.toString,totalElapsedTime.toString,
+    val re = new ResourceEntry(rcName,/*rcType,rcUnitName,*/credits.toString,totalElapsedTime.toString,
                        totalUnits.toString,eventEntry.toList)
+    re.unitName = rcUnitName
+    re.resourceType = rcType
+    re
   }
 
   private[this] def resourceEntriesAt(t:Timeslot,w:UserStateMsg) : (List[ResourceEntry],Double) = {
@@ -219,8 +227,11 @@ object AbstractBillEntry {
       val totalCredits = (a.totalCredits.toDouble+b.totalCredits.toDouble).toString
       val totalElapsedTime =  (a.totalElapsedTime.toLong+b.totalElapsedTime.toLong).toString
       val totalUnits =  (a.totalUnits.toDouble+b.totalUnits.toDouble).toString
-      a.copy(a.resourceName,a.resourceType,a.unitName,totalCredits,totalElapsedTime,totalUnits,
+      val ab = a.copy(a.resourceName/*,a.resourceType,a.unitName*/,totalCredits,totalElapsedTime,totalUnits,
              a.details ::: b.details)
+      ab.unitName = a.unitName
+      ab.resourceType = a.resourceType
+      ab
     }
     val map0 = re.foldLeft(TreeMap[String,ResourceEntry]()){ (map,r1) =>
       map.get(r1.resourceName) match {
@@ -232,7 +243,7 @@ object AbstractBillEntry {
     val map1 = map0.foldLeft(TreeMap[String,List[ResourceEntry]]()){ case (map,(_,r1)) =>
       map.get(r1.resourceType) match {
         case None =>  map + ((r1.resourceType,List(r1)))
-        case Some(rl) => (map - r1.resourceType) +  ((r1.resourceName,r1::rl))
+        case Some(rl) => (map - r1.resourceType) +  ((r1.resourceType,r1::rl))
       }
     }
     map1.foldLeft(List[ServiceEntry]()){ case (ret,(serviceName,resList)) =>
@@ -243,33 +254,43 @@ object AbstractBillEntry {
              c+r.totalUnits.toDouble
             )}
       new ServiceEntry(serviceName,totalCredits.toString,
-                       totalElapsedTime.toString,totalUnits.toString,resList) :: ret
+                       totalElapsedTime.toString,totalUnits.toString,
+                       resList.head.unitName,resList) :: ret
     }
   }
 
-  def fromWorkingUserState(t0:Timeslot,userID:String,w:Option[UserStateMsg]) : AbstractBillEntry = {
+  def addMissingServices(se:List[ServiceEntry],re:Map[String,ResourceType]) : List[ServiceEntry]=
+    se:::(re -- se.map(_.serviceName).toSet).foldLeft(List[ServiceEntry]()) { case (ret,(name,typ:ResourceType)) =>
+      new ServiceEntry(name,"0.0","0","0.0",typ.unit,List[ResourceEntry]()) :: ret
+    }
+
+  def fromWorkingUserState(t0:Timeslot,userID:String,w:Option[UserStateMsg],
+                           resourceTypes:Map[String,ResourceType]) : AbstractBillEntry = {
     val t = t0.roundMilliseconds /* we do not care about milliseconds */
     //Console.err.println("Timeslot: " + t0)
     //Console.err.println("After rounding timeslot: " + t)
     val ret = w match {
       case None =>
+          val allMissing = addMissingServices(Nil,resourceTypes)
           new BillEntry(counter.getAndIncrement.toString,
                         userID,"processing",
                         "0.0",
                         "0.0",
                         t.from.getTime.toString,t.to.getTime.toString,
-                        Nil)
+                        allMissing)
       case Some(w) =>
         val wjson = AvroHelpers.jsonStringOfSpecificRecord(w)
         Console.err.println("Working user state: %s".format(wjson))
         val (rcEntries,rcEntriesCredits) = resourceEntriesAt(t,w)
-        val resMap = aggregateResourceEntries(rcEntries)
+        val resList0 = aggregateResourceEntries(rcEntries)
+        val resList1 = addMissingServices(resList0,resourceTypes)
         new BillEntry(counter.getAndIncrement.toString,
                       userID,"ok",
                       w.getTotalCredits.toString,
                       rcEntriesCredits.toString,
-                      t.from.getTime.toString,t.to.getTime.toString,
-                      resMap)
+                      t.from.getTime.toString,
+                      t.to.getTime.toString,
+                      resList1)
     }
     //Console.err.println("JSON: " +  ret.toJsonString)
     ret
index 4da3cf1..f588dc9 100644 (file)
@@ -8,7 +8,7 @@
   "resourceTypes":[
     {
       "name":"diskspace",
-      "unit":"MB/Hr",
+      "unit":"MB-Hr",
       "chargingBehaviorClass":"gr.grnet.aquarium.charging.ContinuousChargingBehavior"
     },
     {
index 6d7de20..1fcff71 100644 (file)
@@ -141,7 +141,7 @@ object JsonLog {
 } */
 
 object MessageService {
-  val rabbitMQEnabled = true //false
+  val rabbitMQEnabled = false
   val debugEnabled = false
 
   def send(event:SpecificRecord) = {