2 * Copyright 2011 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and
31 * documentation are those of the authors and should not be
32 * interpreted as representing official policies, either expressed
33 * or implied, of GRNET S.A.
36 package gr.grnet.aquarium.logic.events
38 import net.liftweb.json.{JsonAST, Xml}
39 import gr.grnet.aquarium.util.json.JsonHelpers
40 import gr.grnet.aquarium.logic.accounting.dsl._
41 import com.ckkloverdos.maybe.Maybe
44 * Event sent to Aquarium by clients for resource accounting.
46 * @author Christos KK Loverdos <loverdos@gmail.com>.
47 * @author Georgios Gousios <gousiosg@gmail.com>.
49 case class ResourceEvent(
50 override val id: String, // The id at the client side (the sender) TODO: Rename to remoteId or something...
51 override val occurredMillis: Long, // When it occurred at client side (the sender)
52 override val receivedMillis: Long, // When it was received by Aquarium
53 userId: String, // The user for which this resource is relevant
54 clientId: String, // The unique client identifier (usually some hash)
55 resource: String, // String representation of the resource type (e.g. "bndup", "vmtime").
56 instanceId: String, // String representation of the resource instance id
59 details: ResourceEvent.Details)
60 extends AquariumEvent(id, occurredMillis, receivedMillis) {
62 def validate() : Boolean = {
66 def safeResource = if(resource eq null) "" else resource
67 def safeInstanceId = if(instanceId eq null) "" else instanceId
69 def hasResource = !safeResource.isEmpty
70 def hasInstanceId = !safeInstanceId.isEmpty
72 def fullResourceInfo = (safeResource, safeInstanceId)
75 * Returns a beautiful string representation of the value.
77 * @param policy The policy to be asked for resources.
78 * @return A beautiful string representation of the value.
80 def beautifyValue(policy: DSLPolicy): String = {
81 policy.findResource(this.resource) match {
82 case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒
83 OnOffPolicyResourceState(this.value).state.toUpperCase
84 case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒
85 OnOffPolicyResourceState(this.value).state.toUpperCase
92 * Returns a beautiful string representation of the value.
94 * @param resourcesMap The resources map to be asked for resources.
95 * @return A beautiful string representation of the value.
97 def beautifyValue(resourcesMap: DSLResourcesMap): String = {
98 resourcesMap.findResource(this.resource) match {
99 case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒
100 OnOffPolicyResourceState(this.value).state.toUpperCase
101 case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒
102 OnOffPolicyResourceState(this.value).state.toUpperCase
109 * Return `true` iff this is an event regarding a resource with an
110 * [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]].
112 def isOnOffEvent(policy: DSLPolicy): Boolean = {
113 policy.findResource(this.resource).map(_.costPolicy) match {
114 case Some(OnOffCostPolicy) ⇒ true
120 * Return `true` iff this is an event regarding a resource with an
121 * [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]] and a
124 def isOnEvent(policy: DSLPolicy): Boolean = {
125 policy.findResource(this.resource) match {
126 case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒
127 OnOffPolicyResourceState(this.value).isOn
128 case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒
129 OnOffPolicyResourceState(this.value).isOn
136 * Return `true` iff this is an event regarding a resource with an
137 * [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]] and a
138 * `value` of `"off"`.
140 def isOffEvent(policy: DSLPolicy): Boolean = {
141 policy.findResource(this.resource) match {
142 case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒
143 OnOffPolicyResourceState(this.value).isOff
144 case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒
145 OnOffPolicyResourceState(this.value).isOff
151 def copyWithReceivedMillis(millis: Long) = copy(receivedMillis = millis)
154 * Find the cost policy of the resource named in this resource event.
156 * We do not expect cost policies for resources to change, because they are supposed
157 * to be one of their constant characteristics. That is why do not issue a time-dependent
158 * query here for the event's current policy.
160 * Should the need arises to change the cost policy for a resource, this is a good enough
161 * reason to consider creating another type of resource.
163 def findCostPolicy(defaultPolicy: DSLPolicy): Maybe[DSLCostPolicy] = {
164 defaultPolicy.findResource(this.safeResource).map(_.costPolicy): Maybe[DSLCostPolicy]
168 object ResourceEvent {
169 type Details = Map[String, String]
171 type ResourceType = String
172 type ResourceIdType = String
173 type FullResourceType = (ResourceType, ResourceIdType)
175 def fromJson(json: String): ResourceEvent = {
176 JsonHelpers.jsonToObject[ResourceEvent](json)
179 def fromJValue(jsonAST: JsonAST.JValue): ResourceEvent = {
180 JsonHelpers.jValueToObject[ResourceEvent](jsonAST)
183 def fromBytes(bytes: Array[Byte]): ResourceEvent = {
184 JsonHelpers.jsonBytesToObject[ResourceEvent](bytes)
187 def fromXml(xml: String): ResourceEvent = {
188 fromJValue(Xml.toJson(scala.xml.XML.loadString(xml)))
192 final val _id = "_id"
194 final val userId = "userId"
195 //final val timestamp = "timestamp" // TODO: deprecate in favor of "occurredMillis"
196 final val occurredMillis = "occurredMillis"
197 final val receivedMillis = "receivedMillis"
198 final val clientId = "clientId"
199 final val resource = "resource"
200 final val resourceId = "resourceId"
201 final val eventVersion = "eventVersion"
202 final val value = "value"
203 final val details = "details"
205 // ResourceType: VMTime
206 final val vmId = "vmId"
207 final val action = "action" // "on", "off"