root / src / main / scala / gr / grnet / aquarium / store / memory / MemStore.scala @ f9c6a8eb
History | View | Annotate | Download (8.1 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.store.memory |
37 |
|
38 |
import gr.grnet.aquarium.user.UserState |
39 |
import gr.grnet.aquarium.Configurable |
40 |
import com.ckkloverdos.props.Props |
41 |
import com.ckkloverdos.maybe.{NoVal, Just, Maybe} |
42 |
import gr.grnet.aquarium.store._ |
43 |
import scala.collection.JavaConversions._ |
44 |
import java.util.Date |
45 |
import collection.mutable.ConcurrentMap |
46 |
import gr.grnet.aquarium.logic.events.{WalletEntry, ResourceEvent, UserEvent, PolicyEntry} |
47 |
import java.util.concurrent.ConcurrentHashMap |
48 |
import gr.grnet.aquarium.util.date.DateCalculator |
49 |
|
50 |
/** |
51 |
* An implementation of various stores that persists data in memory |
52 |
* |
53 |
* @author Christos KK Loverdos <loverdos@gmail.com> |
54 |
* @author Georgios Gousios <gousiosg@gmail.com> |
55 |
*/ |
56 |
|
57 |
class MemStore extends UserStateStore |
58 |
with Configurable with PolicyStore |
59 |
with ResourceEventStore with UserEventStore |
60 |
with WalletEntryStore |
61 |
with StoreProvider { |
62 |
|
63 |
private[this] val userStateByUserId = new ConcurrentHashMap[String, Just[UserState]]() |
64 |
private val policyById: ConcurrentMap[String, PolicyEntry] = new ConcurrentHashMap[String, PolicyEntry]() |
65 |
private[this] val walletEntriesById: ConcurrentMap[String, WalletEntry] = new ConcurrentHashMap[String, WalletEntry]() |
66 |
private val userEventById: ConcurrentMap[String, UserEvent] = new ConcurrentHashMap[String, UserEvent]() |
67 |
private[this] val resourceEventsById: ConcurrentMap[String, ResourceEvent] = new ConcurrentHashMap[String, ResourceEvent]() |
68 |
|
69 |
def configure(props: Props) = { |
70 |
} |
71 |
|
72 |
//+ StoreProvider |
73 |
def userStateStore = this |
74 |
|
75 |
def resourceEventStore = this |
76 |
|
77 |
def walletEntryStore = this |
78 |
|
79 |
def userEventStore = this |
80 |
|
81 |
def policyStore = this |
82 |
//- StoreProvider |
83 |
|
84 |
|
85 |
def storeUserState(userState: UserState): Maybe[RecordID] = { |
86 |
val userId = userState.userId |
87 |
val userStateJ = Just(userState) |
88 |
userStateByUserId.put(userId, userStateJ) |
89 |
Just(RecordID(userId)) |
90 |
} |
91 |
|
92 |
def findUserStateByUserId(userId: String) = { |
93 |
userStateByUserId.get(userId) match { |
94 |
case null ⇒ NoVal |
95 |
case userStateJ ⇒ userStateJ |
96 |
} |
97 |
} |
98 |
|
99 |
def deleteUserState(userId: String) { |
100 |
if (userStateByUserId.containsKey(userId)) |
101 |
userStateByUserId.remove(userId) |
102 |
} |
103 |
|
104 |
//- WalletEntryStore |
105 |
def storeWalletEntry(entry: WalletEntry): Maybe[RecordID] = { |
106 |
walletEntriesById.put(entry.id, entry) |
107 |
Just(RecordID(entry.id)) |
108 |
} |
109 |
|
110 |
def findWalletEntryById(id: String): Maybe[WalletEntry] = { |
111 |
Maybe(walletEntriesById.apply(id)) |
112 |
} |
113 |
|
114 |
def findUserWalletEntries(userId: String): List[WalletEntry] = { |
115 |
walletEntriesById.valuesIterator.filter(_.userId == userId).toList |
116 |
} |
117 |
|
118 |
def findUserWalletEntriesFromTo(userId: String, from: Date, to: Date): List[WalletEntry] = { |
119 |
walletEntriesById.valuesIterator.filter { we ⇒ |
120 |
val receivedDate = we.receivedDate |
121 |
|
122 |
we.userId == userId && |
123 |
( (from before receivedDate) || (from == receivedDate) ) && |
124 |
( (to after receivedDate) || (to == receivedDate) ) |
125 |
true |
126 |
}.toList |
127 |
} |
128 |
|
129 |
def findLatestUserWalletEntries(userId: String): Maybe[List[WalletEntry]] = NoVal |
130 |
|
131 |
def findPreviousEntry(userId: String, |
132 |
resource: String, |
133 |
instanceId: String, |
134 |
finalized: Option[Boolean]): List[WalletEntry] = Nil |
135 |
|
136 |
def findWalletEntriesAfter(userId: String, from: Date): List[WalletEntry] = { |
137 |
walletEntriesById.valuesIterator.filter { we ⇒ |
138 |
val occurredDate = we.occurredDate |
139 |
|
140 |
we.userId == userId && |
141 |
( (from before occurredDate) || (from == occurredDate) ) |
142 |
}.toList |
143 |
} |
144 |
//- WalletEntryStore |
145 |
|
146 |
//+ ResourceEventStore |
147 |
def storeResourceEvent(event: ResourceEvent) = { |
148 |
resourceEventsById(event.id) = event |
149 |
Just(RecordID(event.id)) |
150 |
} |
151 |
|
152 |
def findResourceEventById(id: String) = { |
153 |
Maybe(resourceEventsById(id)) |
154 |
} |
155 |
|
156 |
def findResourceEventsByUserId(userId: String) |
157 |
(sortWith: Option[(ResourceEvent, ResourceEvent) => Boolean]): List[ResourceEvent] = { |
158 |
val byUserId = resourceEventsById.valuesIterator.filter(_.userId == userId).toArray |
159 |
val sorted = sortWith match { |
160 |
case Some(sorter) ⇒ |
161 |
byUserId.sortWith(sorter) |
162 |
case None ⇒ |
163 |
byUserId |
164 |
} |
165 |
|
166 |
sorted.toList |
167 |
} |
168 |
|
169 |
def findResourceEventsByUserIdAfterTimestamp(userId: String, timestamp: Long): List[ResourceEvent] = { |
170 |
resourceEventsById.valuesIterator.filter { ev ⇒ |
171 |
ev.userId == userId && |
172 |
(ev.occurredMillis > timestamp) |
173 |
}.toList |
174 |
} |
175 |
|
176 |
def findResourceEventHistory(userId: String, |
177 |
resName: String, |
178 |
instid: Option[String], |
179 |
upTo: Long): List[ResourceEvent] = { |
180 |
Nil |
181 |
} |
182 |
|
183 |
def findResourceEventsForReceivedPeriod(userId: String, |
184 |
startTimeMillis: Long, |
185 |
stopTimeMillis: Long): List[ResourceEvent] = { |
186 |
resourceEventsById.valuesIterator.filter { ev ⇒ |
187 |
ev.userId == userId && |
188 |
ev.receivedMillis >= startTimeMillis && |
189 |
ev.receivedMillis <= stopTimeMillis |
190 |
}.toList |
191 |
} |
192 |
|
193 |
def countOutOfSyncEventsForBillingMonth(userId: String, yearOfBillingMonth: Int, billingMonth: Int): Maybe[Long] = Maybe { |
194 |
val billingMonthDate = new DateCalculator(yearOfBillingMonth, billingMonth) |
195 |
val billingDateStart = billingMonthDate |
196 |
val billingDateEnd = billingDateStart.endOfThisMonth |
197 |
resourceEventsById.valuesIterator.filter { case ev ⇒ |
198 |
// out of sync events are those that were received in the billing month but occurred in previous months |
199 |
val receivedMillis = ev.receivedMillis |
200 |
val occurredMillis = ev.occurredMillis |
201 |
|
202 |
billingDateStart.afterEqMillis(receivedMillis) && // the events that... |
203 |
billingDateEnd.beforeEqMillis (receivedMillis) && // ...were received withing the billing month |
204 |
( // |
205 |
billingDateStart.afterMillis(occurredMillis) // but occurred before the billing period |
206 |
) |
207 |
}.size.toLong |
208 |
} |
209 |
//- ResourceEventStore |
210 |
|
211 |
def storeUserEvent(event: UserEvent) = {userEventById += (event.id -> event); Just(RecordID(event.id))} |
212 |
|
213 |
def findUserEventById(id: String) = Maybe{userEventById.getOrElse(id, null)} |
214 |
|
215 |
def findUserEventsByUserId(userId: String) = userEventById.values.filter{v => v.userId == userId}.toList |
216 |
|
217 |
def loadPolicies(after: Long) = policyById.values.foldLeft(List[PolicyEntry]()){ |
218 |
(acc, v) => if(v.validFrom > after) v :: acc else acc |
219 |
} |
220 |
|
221 |
def storePolicy(policy: PolicyEntry) = {policyById += (policy.id -> policy); Just(RecordID(policy.id))} |
222 |
|
223 |
def updatePolicy(policy: PolicyEntry) = storePolicy(policy) |
224 |
} |