root / src / main / scala / gr / grnet / aquarium / logic / events / ResourceEvent.scala @ 28bb45ec
History | View | Annotate | Download (10 kB)
1 |
/* |
---|---|
2 |
* Copyright 2011 GRNET S.A. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or |
5 |
* without modification, are permitted provided that the following |
6 |
* conditions are met: |
7 |
* |
8 |
* 1. Redistributions of source code must retain the above |
9 |
* copyright notice, this list of conditions and the following |
10 |
* disclaimer. |
11 |
* |
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. |
16 |
* |
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. |
29 |
* |
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. |
34 |
*/ |
35 |
|
36 |
package gr.grnet.aquarium.logic.events |
37 |
|
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.{MaybeOption, Maybe} |
42 |
import java.util.Date |
43 |
import gr.grnet.aquarium.util.date.DateCalculator |
44 |
|
45 |
/** |
46 |
* Event sent to Aquarium by clients for resource accounting. |
47 |
* |
48 |
* @author Christos KK Loverdos <loverdos@gmail.com>. |
49 |
* @author Georgios Gousios <gousiosg@gmail.com>. |
50 |
*/ |
51 |
case class ResourceEvent( |
52 |
override val id: String, // The id at the client side (the sender) TODO: Rename to remoteId or something... |
53 |
override val occurredMillis: Long, // When it occurred at client side (the sender) |
54 |
override val receivedMillis: Long, // When it was received by Aquarium |
55 |
userId: String, // The user for which this resource is relevant |
56 |
clientId: String, // The unique client identifier (usually some hash) |
57 |
resource: String, // String representation of the resource type (e.g. "bndup", "vmtime"). |
58 |
instanceId: String, // String representation of the resource instance id |
59 |
eventVersion: String, |
60 |
value: Double, |
61 |
details: ResourceEvent.Details) |
62 |
extends AquariumEvent(id, occurredMillis, receivedMillis) { |
63 |
|
64 |
def validate() : Boolean = { |
65 |
!safeResource.isEmpty |
66 |
} |
67 |
|
68 |
def safeResource = if(resource eq null) "" else resource |
69 |
def safeInstanceId = if(instanceId eq null) "" else instanceId |
70 |
|
71 |
def hasResource = !safeResource.isEmpty |
72 |
def hasInstanceId = !safeInstanceId.isEmpty |
73 |
|
74 |
def fullResourceInfo = (safeResource, safeInstanceId) |
75 |
|
76 |
def isOccurredWithinMillis(fromMillis: Long, toMillis: Long): Boolean = { |
77 |
fromMillis <= occurredMillis && occurredMillis <= toMillis |
78 |
} |
79 |
|
80 |
def isOccurredWithinDates(fromDate: Date, toDate: Date): Boolean = { |
81 |
fromDate.getTime <= occurredMillis && occurredMillis <= toDate.getTime |
82 |
} |
83 |
|
84 |
def isReceivedWithinMillis(fromMillis: Long, toMillis: Long): Boolean = { |
85 |
fromMillis <= receivedMillis && receivedMillis <= toMillis |
86 |
} |
87 |
|
88 |
def isReceivedWithinDates(fromDate: Date, toDate: Date): Boolean = { |
89 |
fromDate.getTime <= receivedMillis && receivedMillis <= toDate.getTime |
90 |
} |
91 |
|
92 |
def isOccurredOrReceivedWithinMillis(fromMillis: Long, toMillis: Long): Boolean = { |
93 |
isOccurredWithinMillis(fromMillis, toMillis) || |
94 |
isReceivedWithinMillis(fromMillis, toMillis) |
95 |
} |
96 |
|
97 |
def isOccurredOrReceivedWithinDates(fromDate: Date, toDate: Date): Boolean = { |
98 |
isOccurredWithinDates(fromDate, toDate) || |
99 |
isReceivedWithinDates(fromDate, toDate) |
100 |
} |
101 |
|
102 |
def toDebugString(resourcesMap: DSLResourcesMap, useOnlyInstanceId: Boolean): String = { |
103 |
val instanceInfo = if(useOnlyInstanceId) instanceId else "%s::%s".format(resource, instanceId) |
104 |
val bvalue = beautifyValue(resourcesMap) |
105 |
val occurredFormatted = new DateCalculator(occurredMillis).toString |
106 |
if(occurredMillis == receivedMillis) { |
107 |
"EVENT(%s, [%s], %s, %s, %s, %s, %s)".format( |
108 |
id, |
109 |
occurredFormatted, |
110 |
bvalue, |
111 |
instanceInfo, |
112 |
details, |
113 |
userId, |
114 |
clientId |
115 |
) |
116 |
} else { |
117 |
"EVENT(%s, [%s], [%s], %s, %s, %s, %s, %s)".format( |
118 |
id, |
119 |
occurredFormatted, |
120 |
new DateCalculator(receivedMillis), |
121 |
bvalue, |
122 |
instanceInfo, |
123 |
details, |
124 |
userId, |
125 |
clientId |
126 |
) |
127 |
} |
128 |
} |
129 |
|
130 |
private[this] |
131 |
def beatifyValue(resourceProvider: (String) ⇒ Option[DSLResource]): String = { |
132 |
resourceProvider(this.resource) match { |
133 |
case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒ |
134 |
OnOffPolicyResourceState(this.value).state.toUpperCase |
135 |
case Some(rc @ DSLComplexResource(_, _, _, _)) ⇒ |
136 |
"%s [%s]".format(value, rc.unit) |
137 |
case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒ |
138 |
OnOffPolicyResourceState(this.value).state.toUpperCase |
139 |
case Some(rc @ DSLSimpleResource(_, _, _)) ⇒ |
140 |
"%s [%s]".format(value, rc.unit) |
141 |
case _ ⇒ |
142 |
value.toString |
143 |
} |
144 |
} |
145 |
|
146 |
/** |
147 |
* Returns a beautiful string representation of the value. |
148 |
* |
149 |
* @param policy The policy to be asked for resources. |
150 |
* @return A beautiful string representation of the value. |
151 |
*/ |
152 |
def beautifyValue(policy: DSLPolicy): String = { |
153 |
beatifyValue(policy.findResource) |
154 |
} |
155 |
|
156 |
/** |
157 |
* Returns a beautiful string representation of the value. |
158 |
* |
159 |
* @param resourcesMap The resources map to be asked for resources. |
160 |
* @return A beautiful string representation of the value. |
161 |
*/ |
162 |
def beautifyValue(resourcesMap: DSLResourcesMap): String = { |
163 |
beatifyValue(resourcesMap.findResource) |
164 |
} |
165 |
|
166 |
/** |
167 |
* Return `true` iff this is an event regarding a resource with an |
168 |
* [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]]. |
169 |
*/ |
170 |
def isOnOffEvent(policy: DSLPolicy): Boolean = { |
171 |
policy.findResource(this.resource).map(_.costPolicy) match { |
172 |
case Some(OnOffCostPolicy) ⇒ true |
173 |
case _ ⇒ false |
174 |
} |
175 |
} |
176 |
|
177 |
/** |
178 |
* Return `true` iff this is an event regarding a resource with an |
179 |
* [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]] and a |
180 |
* `value` of `"on"`. |
181 |
*/ |
182 |
def isOnEvent(policy: DSLPolicy): Boolean = { |
183 |
policy.findResource(this.resource) match { |
184 |
case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒ |
185 |
OnOffPolicyResourceState(this.value).isOn |
186 |
case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒ |
187 |
OnOffPolicyResourceState(this.value).isOn |
188 |
case _ ⇒ |
189 |
false |
190 |
} |
191 |
} |
192 |
|
193 |
/** |
194 |
* Return `true` iff this is an event regarding a resource with an |
195 |
* [[gr.grnet.aquarium.logic.accounting.dsl.OnOffCostPolicy]] and a |
196 |
* `value` of `"off"`. |
197 |
*/ |
198 |
def isOffEvent(policy: DSLPolicy): Boolean = { |
199 |
policy.findResource(this.resource) match { |
200 |
case Some(DSLComplexResource(_, _, OnOffCostPolicy, _)) ⇒ |
201 |
OnOffPolicyResourceState(this.value).isOff |
202 |
case Some(DSLSimpleResource(_, _, OnOffCostPolicy)) ⇒ |
203 |
OnOffPolicyResourceState(this.value).isOff |
204 |
case _ ⇒ |
205 |
false |
206 |
} |
207 |
} |
208 |
|
209 |
def copyWithReceivedMillis(millis: Long) = copy(receivedMillis = millis) |
210 |
|
211 |
/** |
212 |
* Find the cost policy of the resource named in this resource event. |
213 |
* |
214 |
* We do not expect cost policies for resources to change, because they are supposed |
215 |
* to be one of their constant characteristics. That is why do not issue a time-dependent |
216 |
* query here for the event's current policy. |
217 |
* |
218 |
* Should the need arises to change the cost policy for a resource, this is a good enough |
219 |
* reason to consider creating another type of resource. |
220 |
*/ |
221 |
def findCostPolicyM(defaultPolicy: DSLPolicy): Maybe[DSLCostPolicy] = { |
222 |
defaultPolicy.findResource(this.safeResource).map(_.costPolicy): Maybe[DSLCostPolicy] |
223 |
} |
224 |
|
225 |
/** |
226 |
* Find the cost policy of the resource named in this resource event. |
227 |
* |
228 |
* We do not expect cost policies for resources to change, because they are supposed |
229 |
* to be one of their constant characteristics. That is why do not issue a time-dependent |
230 |
* query here for the event's current policy. |
231 |
* |
232 |
* Should the need arises to change the cost policy for a resource, this is a good enough |
233 |
* reason to consider creating another type of resource. |
234 |
*/ |
235 |
def findCostPolicy(resourcesMap: DSLResourcesMap): Option[DSLCostPolicy] = { |
236 |
resourcesMap.findResource(this.safeResource).map(_.costPolicy) |
237 |
} |
238 |
} |
239 |
|
240 |
object ResourceEvent { |
241 |
type Details = Map[String, String] |
242 |
|
243 |
type ResourceType = String |
244 |
type ResourceIdType = String |
245 |
type FullResourceType = (ResourceType, ResourceIdType) |
246 |
|
247 |
def fromJson(json: String): ResourceEvent = { |
248 |
JsonHelpers.jsonToObject[ResourceEvent](json) |
249 |
} |
250 |
|
251 |
def fromJValue(jsonAST: JsonAST.JValue): ResourceEvent = { |
252 |
JsonHelpers.jValueToObject[ResourceEvent](jsonAST) |
253 |
} |
254 |
|
255 |
def fromBytes(bytes: Array[Byte]): ResourceEvent = { |
256 |
JsonHelpers.jsonBytesToObject[ResourceEvent](bytes) |
257 |
} |
258 |
|
259 |
def fromXml(xml: String): ResourceEvent = { |
260 |
fromJValue(Xml.toJson(scala.xml.XML.loadString(xml))) |
261 |
} |
262 |
|
263 |
object JsonNames { |
264 |
final val _id = "_id" |
265 |
final val id = "id" |
266 |
final val userId = "userId" |
267 |
//final val timestamp = "timestamp" // TODO: deprecate in favor of "occurredMillis" |
268 |
final val occurredMillis = "occurredMillis" |
269 |
final val receivedMillis = "receivedMillis" |
270 |
final val clientId = "clientId" |
271 |
final val resource = "resource" |
272 |
final val resourceId = "resourceId" |
273 |
final val eventVersion = "eventVersion" |
274 |
final val value = "value" |
275 |
final val details = "details" |
276 |
|
277 |
// ResourceType: VMTime |
278 |
final val vmId = "vmId" |
279 |
final val action = "action" // "on", "off" |
280 |
} |
281 |
} |