Statistics
| Branch: | Tag: | Revision:

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
}