Statistics
| Branch: | Tag: | Revision:

root / src / main / scala / gr / grnet / aquarium / logic / events / ResourceType.scala @ 87caa095

History | View | Annotate | Download (6.9 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 gr.grnet.aquarium.util.TimeHelpers.nowMillis
39
import gr.grnet.aquarium.user._
40

    
41

    
42
/**
43
 * This is an object representation for a resource name, which provides convenient querying methods.
44
 *
45
 * Also, a `ResourceType` knows how to compute a state change from a particular `ResourceEvent`.
46
 *
47
 * @author Christos KK Loverdos <loverdos@gmail.com>
48
 */
49
sealed abstract class ResourceType(_name: String) {
50
  def resourceName = _name
51

    
52
  /**
53
   * Return true if the resource type must lead to wallet entries generation and, thus, credit diffs.
54
   *
55
   * Normally, this should always be the case.
56
   */
57
  def isBillableType = true
58

    
59
  /**
60
   * A resource type is independent if it can, by itself only, create a finalized wallet entry (that is,
61
   * it can create, by itself only, credits).
62
   *
63
   * It is dependent if it needs one or more other events of he same type to
64
   */
65
  def isIndependentType = true
66

    
67
  def isKnownType = true
68
  def isDiskSpace = false
69
  def isVMTime = false
70
  def isBandwidthUpload = false
71
  def isBandwidthDownload = false
72

    
73
  /**
74
   * Calculates the new `UserState` based on the provided resource event, the calculated wallet entries
75
   * and the current `UserState`.
76
   *
77
   * This method is an implementation detail and is not exposed. The actual user-level API is provided in `ResourceEvent`.
78
   */
79
  private[events] final
80
  def calcStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState): UserState = {
81
    val otherState = calcOtherStateChange(resourceEvent, walletEntries, userState)
82
    val newCredits = calcNewCreditSnapshot(walletEntries, userState)
83
    otherState.copy(credits = newCredits)
84
  }
85

    
86
  private[events]
87
  def calcOtherStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState): UserState
88
  
89
  private[events] final
90
  def calcNewCreditSnapshot(walletEntries: List[WalletEntry], userState: UserState): CreditSnapshot = {
91
    val newCredits = for {
92
      walletEntry <- walletEntries if(walletEntry.finalized)
93
    } yield walletEntry.value.toDouble
94

    
95
    val newCreditSum = newCredits.sum
96
    val now = System.currentTimeMillis()
97

    
98
    CreditSnapshot(userState.credits.data + newCreditSum, now)
99
  }
100
}
101

    
102
/**
103
 * Companion object used to parse a resource name and provide an object representation in the form
104
 * of a `ResourceType`.
105
 *
106
 * Known resource names, which represent Aquarium resources, are like "bndup", "vmtime" etc. and they are all
107
 * defined in `ResourceNames`.
108
 *
109
 * @author Christos KK Loverdos <loverdos@gmail.com>
110
 */
111
object ResourceType {
112
  def fromName(name: String): ResourceType = {
113
    name match {
114
      case ResourceNames.bnddown ⇒ BandwidthDown
115
      case ResourceNames.bndup   ⇒ BandwidthUp
116
      case ResourceNames.vmtime  ⇒ VMTime
117
      case _                     ⇒ UnknownResourceType(name)
118
    }
119
  }
120

    
121
  def fromResourceEvent(resourceEvent: ResourceEvent): ResourceType = fromName(resourceEvent.resource)
122
}
123

    
124
case object BandwidthDown extends ResourceType(ResourceNames.bnddown) {
125
  override def isBandwidthDownload = true
126

    
127
  private[events]
128
  def calcOtherStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState) = {
129
    val oldBandwidthDownValue = userState.bandwidthDown.data
130
    val bandwidthDownDiff = resourceEvent.value
131

    
132
    val newBandwidth = BandwidthDownSnapshot(oldBandwidthDownValue + bandwidthDownDiff, nowMillis)
133

    
134
    userState.copy(bandwidthDown = newBandwidth)
135
  }
136
}
137

    
138
case object BandwidthUp extends ResourceType(ResourceNames.bndup) {
139
  override def isBandwidthUpload = true
140

    
141
  private[events]
142
  def calcOtherStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState) = {
143
    val oldBandwidthUpValue = userState.bandwidthUp.data
144
    val bandwidthUpDiff = resourceEvent.value
145

    
146
    val newBandwidth = BandwidthUpSnapshot(oldBandwidthUpValue + bandwidthUpDiff, nowMillis)
147

    
148
    userState.copy(bandwidthUp = newBandwidth)
149
  }
150
}
151

    
152
case object VMTime extends ResourceType(ResourceNames.vmtime) {
153
  override def isVMTime = true
154

    
155
  override def isIndependentType = false
156

    
157
  def isVMTimeOn(eventDetails: ResourceEvent.Details) = eventDetails.get(ResourceEvent.JsonNames.action) match {
158
    case Some("on") ⇒ true
159
    case Some("up") ⇒ true
160
    case _          ⇒ false
161
  }
162
  
163
  def isVMTimeOff(eventDetails: ResourceEvent.Details) = eventDetails.get(ResourceEvent.JsonNames.action) match {
164
    case Some("off")  ⇒ true
165
    case Some("down") ⇒ true
166
    case _            ⇒ false
167
  }
168

    
169
  private[events] def calcOtherStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState) = {
170
    // FIXME: implement
171
    userState
172
  }
173
}
174

    
175
case object DiskSpace extends ResourceType(ResourceNames.dsksp) {
176
  override def isDiskSpace = true
177

    
178
  private[events] def calcOtherStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState) = {
179
    val oldDiskSpaceValue = userState.diskSpace.data
180
    val diskSpaceDiff = resourceEvent.value
181
    val newDiskSpace = DiskSpaceSnapshot(oldDiskSpaceValue + diskSpaceDiff, nowMillis)
182
    userState.copy(diskSpace = newDiskSpace)
183
  }
184
}
185

    
186
case class UnknownResourceType(originalName: String) extends ResourceType(ResourceNames.unknown) {
187
  override def isKnownType = false
188

    
189
  private[events] def
190
  calcOtherStateChange(resourceEvent: ResourceEvent, walletEntries: List[WalletEntry], userState: UserState) = userState
191
}