WIP: Remodeling events
authorChristos KK Loverdos <loverdos@gmail.com>
Fri, 20 Apr 2012 12:29:50 +0000 (15:29 +0300)
committerChristos KK Loverdos <loverdos@gmail.com>
Fri, 20 Apr 2012 12:29:50 +0000 (15:29 +0300)
12 files changed:
.gitignore
src/main/scala/gr/grnet/aquarium/events/AquariumEvent.scala
src/main/scala/gr/grnet/aquarium/events/AquariumEventModel.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/events/IMEvent.scala
src/main/scala/gr/grnet/aquarium/events/IMEventModel.scala [new file with mode: 0644]
src/main/scala/gr/grnet/aquarium/events/ResourceEvent.scala
src/main/scala/gr/grnet/aquarium/events/WalletEntry.scala
src/main/scala/gr/grnet/aquarium/simulation/ResourceInstanceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdBandwidthInstanceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdDiskspaceInstanceSim.scala
src/main/scala/gr/grnet/aquarium/simulation/StdVMTimeInstanceSim.scala
src/main/scala/gr/grnet/aquarium/store/mongodb/MongoDBStore.scala

index edaf413..d7a52a5 100644 (file)
@@ -36,6 +36,7 @@ doc/arch/aquarium.ent
 doc/arch/arch.texshop
 build.log
 _gitstats/
+_localrest
 *.aquarium.properties
 sshfs/
 aquarium-dist/
index 96fb1e5..96076be 100644 (file)
@@ -37,7 +37,6 @@ package gr.grnet.aquarium
 package events
 
 
-import util.json.JsonSupport
 import util.xml.XmlSupport
 import util.Loggable
 
@@ -51,7 +50,7 @@ abstract class AquariumEvent(
     val id: String,           // The id at the client side (the sender) TODO: Rename to remoteId or something...
     val occurredMillis: Long, // When it occurred at client side (the sender)
     val receivedMillis: Long) // When it was received by Aquarium
-  extends JsonSupport
+  extends AquariumEventModel
   with    XmlSupport
   with    Loggable {
 
@@ -61,9 +60,11 @@ abstract class AquariumEvent(
     toJson.getBytes("UTF-8")
   }
 
-  /**
-   * Return a new instance with all state the same as this one except for `receivedMillis`, which
-   * acquires the new value.
-   */
+  def storeID: Option[AnyRef] = Some(id)
+
+  def details: Map[String, String] = Map()
+
+  def eventVersion = "1.0"
+
   def copyWithReceivedMillis(receivedMillis: Long): AquariumEvent
 }
diff --git a/src/main/scala/gr/grnet/aquarium/events/AquariumEventModel.scala b/src/main/scala/gr/grnet/aquarium/events/AquariumEventModel.scala
new file mode 100644 (file)
index 0000000..5358bcd
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.events
+
+import gr.grnet.aquarium.util.json.JsonSupport
+
+/**
+ * The base model for all events coming from external systems.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+
+trait AquariumEventModel extends JsonSupport {
+  def id: String
+  def occurredMillis: Long
+  def receivedMillis: Long
+//  def userID: String
+  def eventVersion: String
+  def details: Map[String, String]
+
+  /**
+   * The ID given to this event if/when persisted to a store.
+   * The exact type of the id is store-specific.
+   */
+  def storeID: Option[AnyRef]
+}
index e729ed6..60478af 100644 (file)
@@ -55,17 +55,25 @@ case class  IMEvent(
     clientID: String,
     isActive: Boolean,
     role: String,
-    eventVersion: String,
+    override val eventVersion: String,
     eventType: String,
-    details: IMEvent.Details,
-    _id: AnyRef = new ObjectId())
-  extends AquariumEvent(id, occurredMillis, receivedMillis) {
+    override val details: Map[String, String],
+    _id: ObjectId = new ObjectId())
+  extends AquariumEvent(id, occurredMillis, receivedMillis) with IMEventModel {
+
 
 //  assert(eventType.equalsIgnoreCase(IMEvent.EventTypes.create) ||
 //    eventType.equalsIgnoreCase(IMEvent.EventTypes.modify))
 
 //  assert(!role.isEmpty)
 
+  override def storeID = {
+    _id match {
+      case null ⇒ None
+      case _    ⇒ Some(_id)
+    }
+  }
+
   /**
    * Validate this event according to the following rules:
    *
@@ -117,8 +125,6 @@ object IMEvent {
     val modify = "modify"
   }
 
-  type Details = Map[String, String]
-
   def fromJson(json: String): IMEvent = {
     StdConverters.StdConverters.convertEx[IMEvent](JsonTextFormat(json))
   }
diff --git a/src/main/scala/gr/grnet/aquarium/events/IMEventModel.scala b/src/main/scala/gr/grnet/aquarium/events/IMEventModel.scala
new file mode 100644 (file)
index 0000000..72bb1fa
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.events
+
+/**
+ * The model of any event sent from the `Identity Management` (IM) external system.
+ *
+ * We use this to not reveal storage-specific stuff, like IDs.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>
+ */
+
+trait IMEventModel extends AquariumEventModel {
+  def clientID: String
+  def isActive: Boolean
+  def role: String
+  def eventType: String
+}
index bc8da01..353facd 100644 (file)
@@ -58,9 +58,9 @@ case class ResourceEvent(
     clientID: String,                  // The unique client identifier (usually some hash)
     resource: String,                  // String representation of the resource type (e.g. "bndup", "vmtime").
     instanceID: String,                // String representation of the resource instance id
-    eventVersion: String,
+    override val eventVersion: String,
     value: Double,
-    details: ResourceEvent.Details)
+    override val details: Map[String, String])
   extends AquariumEvent(id, occurredMillis, receivedMillis) {
 
   def validate() : Boolean = {
@@ -241,9 +241,6 @@ case class ResourceEvent(
 }
 
 object ResourceEvent {
-  type Details = Map[String, String]
-  final val EmptyDetails: Details = Map()
-
   type ResourceType = String
   type ResourceIdType = String
   type FullResourceType = (ResourceType, ResourceIdType)
@@ -258,11 +255,11 @@ object ResourceEvent {
     StdConverters.StdConverters.convertEx[ResourceEvent](JsonTextFormat(makeString(bytes)))
   }
 
-  def setAquariumSynthetic(map: ResourceEvent.Details): ResourceEvent.Details = {
+  def setAquariumSynthetic(map: Map[String, String]): Map[String, String] = {
     map.updated(JsonNames.details_aquarium_is_synthetic, "true")
   }
 
-  def setAquariumSyntheticAndImplicitEnd(map: ResourceEvent.Details): ResourceEvent.Details = {
+  def setAquariumSyntheticAndImplicitEnd(map: Map[String, String]): Map[String, String] = {
     map.
       updated(JsonNames.details_aquarium_is_synthetic, "true").
       updated(JsonNames.details_aquarium_is_implicit_end, "true")
index d9ca998..9453852 100644 (file)
@@ -38,6 +38,7 @@ package events
 
 import java.util.Date
 import converter.{JsonTextFormat, StdConverters}
+import util.json.JsonSupport
 
 /**
  * A WalletEntry is a derived entity. Its data represent money/credits and are calculated based on
@@ -61,6 +62,7 @@ case class WalletEntry(
     finalized: Boolean)
   extends AquariumEvent(id, occurredMillis, receivedMillis) {
 
+
   assert(occurredMillis > 0)
   assert(value >= 0F)
   assert(!userId.isEmpty)
index 059668a..3866765 100644 (file)
@@ -54,7 +54,7 @@ class ResourceInstanceSim (val resource: ResourceSim,
   def newResourceEvent(occurredMillis: Long,
                        receivedMillis: Long,
                        value: Double,
-                       details: ResourceEvent.Details,
+                       details: Map[String, String],
                        eventVersion: String = "1.0") = {
 
     val event = ResourceEvent(
index aba19e3..b7be463 100644 (file)
@@ -53,7 +53,7 @@ case class StdBandwidthInstanceSim(override val resource: StdBandwidthResourceSi
 extends ResourceInstanceSim(resource, instanceId, owner, client) {
   def useBandwidth(occurredDate: Date,
                    megaBytes: Double,
-                   details: ResourceEvent.Details = Map(),
+                   details: Map[String, String] = Map(),
                    eventVersion: String = "1.0"): RecordID = {
 
     newResourceEvent(
index a940009..5b62d5f 100644 (file)
@@ -53,7 +53,7 @@ case class StdDiskspaceInstanceSim(override val resource: StdDiskspaceResourceSi
 extends ResourceInstanceSim(resource, instanceId, owner, client) {
   def consumeMB(occurredDate: Date,
                 megaBytes: Double,
-                details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+                details: Map[String, String] = Map(),
                 eventVersion: String = "1.0"): RecordID = {
     newResourceEvent(
       occurredDate.getTime,
@@ -67,7 +67,7 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
 
   def freeMB(occurredDate: Date,
              megaBytes: Double,
-             details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+             details: Map[String, String] = Map(),
              eventVersion: String = "1.0"): RecordID = {
 
     consumeMB(occurredDate, -megaBytes)
@@ -76,7 +76,7 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
   def consumeMB_OutOfSync(occurredDate: Date,
                           outOfSyncHours: Int,
                           megaBytes: Double,
-                          details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+                          details: Map[String, String] = Map(),
                           eventVersion: String = "1.0"): RecordID = {
 
     val occurredDateCalc = new MutableDateCalc(occurredDate)
@@ -95,7 +95,7 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
   def freeMB_OutOfSync(occurredDate: Date,
                        outOfSyncHours: Int,
                        megaBytes: Double,
-                       details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+                       details: Map[String, String] = Map(),
                        eventVersion: String = "1.0"): RecordID = {
 
     consumeMB_OutOfSync(occurredDate, outOfSyncHours, -megaBytes)
index fd363b3..1295d19 100644 (file)
@@ -55,7 +55,7 @@ case class StdVMTimeInstanceSim(override val resource: StdVMTimeResourceSim,
 extends ResourceInstanceSim(resource, instanceId, owner, client) {
 
   def newON(occurredDate: Date,
-            details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+            details: Map[String, String] = Map(),
             eventVersion: String = "1.0"): RecordID = {
     newResourceEvent(
       occurredDate.getTime,
@@ -67,7 +67,7 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
   }
 
   def newOFF(occurredDate: Date,
-             details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+             details: Map[String, String] = Map(),
              eventVersion: String = "1.0"): RecordID = {
     newResourceEvent(
       occurredDate.getTime,
@@ -88,7 +88,7 @@ extends ResourceInstanceSim(resource, instanceId, owner, client) {
 
   def newOFF_OutOfSync(occuredDate: Date,
                        outOfSyncHours: Int,
-                       details: ResourceEvent.Details = ResourceEvent.EmptyDetails,
+                       details: Map[String, String] = Map(),
                        eventVersion: String = "1.0"): RecordID = {
 
     val occurredDateCalc = new MutableDateCalc(occuredDate)
index bf73d35..0edecd8 100644 (file)
@@ -87,7 +87,7 @@ class MongoDBStore(
     db.getCollection(name)
   }
 
-  private[this] def _sortByTimestampAsc[A <: AquariumEvent](one: A, two: A): Boolean = {
+  private[this] def _sortByTimestampAsc[A <: AquariumEventModel](one: A, two: A): Boolean = {
     if (one.occurredMillis > two.occurredMillis) false
     else if (one.occurredMillis < two.occurredMillis) true
     else true
@@ -442,7 +442,8 @@ object MongoDBStore {
     PolicyEntry.fromJson(JSON.serialize(dbObj))
   }
 
-  def findById[A >: Null <: AquariumEvent](id: String, collection: DBCollection, deserializer: (DBObject) => A) : Maybe[A] = Maybe {
+  def findById[A >: Null <: AnyRef](id: String, collection: DBCollection, deserializer: (DBObject) => A) : Maybe[A] =
+    Maybe {
     val query = new BasicDBObject(ResourceJsonNames.id, id)
     val cursor = collection find query
 
@@ -456,7 +457,7 @@ object MongoDBStore {
     }
   }
 
-  def runQuery[A <: AquariumEvent](query: DBObject, collection: DBCollection, orderBy: DBObject = null)
+  def runQuery[A <: AquariumEventModel](query: DBObject, collection: DBCollection, orderBy: DBObject = null)
                                   (deserializer: (DBObject) => A)
                                   (sortWith: Option[(A, A) => Boolean]): List[A] = {
     val cursor0 = collection find query