Tweeking configuration
[aquarium] / src / main / scala / gr / grnet / aquarium / event / resource / ResourceEventModel.scala
1 /*
2  * Copyright 2011-2012 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.event
37 package resource
38
39 import java.util.Date
40 import gr.grnet.aquarium.util.date.MutableDateCalc
41
42 /**
43  * The model of any resource event.
44  *
45  * @author Christos KK Loverdos <loverdos@gmail.com>
46  */
47
48 trait ResourceEventModel extends ExternalEventModel {
49   /**
50    * Identifies the client that sent this event.
51    */
52   def clientID: String
53
54   /**
55    * String representation of the resource type (e.g. "bndup", "vmtime").
56    */
57   def resource: String
58
59   /**
60    * String representation of the resource instance id
61    */
62   def instanceID: String
63
64
65   /**
66    * The resource value.
67    */
68   def value: Double
69
70   def withDetails(newDetails: Map[String, String], newOccurredMillis: Long): ResourceEventModel
71
72   def withDetailsAndValue(newDetails: Map[String, String], newValue: Double, newOccurredMillis: Long): ResourceEventModel
73
74   def safeResource   = if(resource eq null)   "" else resource
75   def safeInstanceId = if(instanceID eq null) "" else instanceID
76
77   def fullResourceInfo = (safeResource, safeInstanceId)
78
79   def occurredDate = new Date(occurredMillis)
80
81   def isOccurredWithinMillis(fromMillis: Long, toMillis: Long): Boolean = {
82     require(fromMillis <= toMillis, "fromMillis <= toMillis")
83     fromMillis <= occurredMillis && occurredMillis <= toMillis
84   }
85
86   def isReceivedWithinMillis(fromMillis: Long, toMillis: Long): Boolean = {
87     require(fromMillis <= toMillis, "fromMillis <= toMillis")
88     fromMillis <= receivedMillis && receivedMillis <= toMillis
89   }
90
91   def isOccurredOrReceivedWithinMillis(fromMillis: Long, toMillis: Long): Boolean = {
92     isOccurredWithinMillis(fromMillis, toMillis) ||
93     isReceivedWithinMillis(fromMillis, toMillis)
94   }
95
96   def isOutOfSyncForBillingMonth(yearOfBillingMonth: Int, billingMonth: Int) = {
97     val billingStartDateCalc = new MutableDateCalc(yearOfBillingMonth, billingMonth)
98     val billingStartMillis = billingStartDateCalc.toMillis
99     // NOTE: no need to `copy` the mutable `billingStartDateCalc` here because we use it once
100     val billingStopMillis  = billingStartDateCalc.goEndOfThisMonth.toMillis
101
102     isOutOfSyncForBillingPeriod(billingStartMillis, billingStopMillis)
103   }
104
105   def isOutOfSyncForBillingPeriod(billingStartMillis: Long, billingStopMillis: Long): Boolean = {
106     isReceivedWithinMillis(billingStartMillis, billingStopMillis) &&
107     (occurredMillis < billingStartMillis || occurredMillis > billingStopMillis)
108   }
109
110   def toDebugString(useOnlyInstanceId: Boolean = false): String = {
111     val instanceInfo = if(useOnlyInstanceId) instanceID else "%s::%s".format(resource, instanceID)
112     val occurredFormatted = new MutableDateCalc(occurredMillis).toYYYYMMDDHHMMSS
113     if(occurredMillis == receivedMillis) {
114       "%sEVENT(%s, [%s], %s, %s, %s, %s, %s)".format(
115         if(isSynthetic) "*" else "",
116         id,
117         occurredFormatted,
118         value,
119         instanceInfo,
120         details,
121         userID,
122         clientID
123       )
124     } else {
125       "%sEVENT(%s, [%s], [%s], %s, %s, %s, %s, %s)".format(
126         if(isSynthetic) "*" else "",
127         id,
128         occurredFormatted,
129         new MutableDateCalc(receivedMillis),
130         value,
131         instanceInfo,
132         details,
133         userID,
134         clientID
135       )
136     }
137   }
138
139   /**
140    * `Synthetic` means that Aquarium has manufactured this resource event for some purpose. For example, the implicitly
141    * issued resource events at the end a a billing period.
142    *
143    * @return `true` iff this resource event is synthetic.
144    */
145   def isSynthetic = {
146     details contains ResourceEventModel.Names.details_aquarium_is_synthetic
147   }
148
149 }
150
151 object ResourceEventModel {
152   type ResourceType = String
153   type ResourceIdType = String
154   type FullResourceType = (ResourceType, ResourceIdType)
155   type FullResourceTypeMap = Map[FullResourceType, ResourceEventModel]
156   type FullMutableResourceTypeMap = scala.collection.mutable.Map[FullResourceType, ResourceEventModel]
157
158   trait NamesT extends ExternalEventModel.NamesT {
159     final val clientID = "clientID"
160     final val resource = "resource"
161     final val instanceID = "instanceID"
162     final val value = "value"
163
164     // This is set in the details map to indicate a synthetic resource event (ie not a real one).
165     // Examples of synthetic resource events are those that are implicitly generated at the
166     // end of the billing period (e.g. `OFF`s).
167     final val details_aquarium_is_synthetic    = "__aquarium_is_synthetic__"
168
169     final val details_aquarium_is_implicit_end = "__aquarium_is_implicit_end__"
170   }
171
172   object Names extends NamesT
173
174   def setAquariumSyntheticAndImplicitEnd(map: Map[String, String]): Map[String, String] = {
175     map.
176       updated(Names.details_aquarium_is_synthetic, "true").
177       updated(Names.details_aquarium_is_implicit_end, "true")
178   }
179
180 }