Use JavaFactory
[aquarium] / src / main / scala / gr / grnet / aquarium / message / avro / MessageFactory.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.message.avro
37
38 import gr.grnet.aquarium.computation.BillingMonthInfo
39 import gr.grnet.aquarium.event.DetailsModel
40 import gr.grnet.aquarium.message.avro.gen._
41 import scala.collection.JavaConverters.mapAsJavaMapConverter
42 import scala.collection.JavaConverters.seqAsJavaListConverter
43 import scala.Predef.Map
44 import gr.grnet.aquarium.policy.ResourceType
45 import gr.grnet.aquarium.util.date.TimeHelpers
46 import gr.grnet.aquarium.Real
47 import gr.grnet.aquarium.util.JavaFactory.{newJList, newJMap}
48 /**
49  * Provides helper methods that construct avro messages.
50  *
51  * @author Christos KK Loverdos <loverdos@gmail.com>
52  */
53 object MessageFactory {
54   def anyValueMsgOfBoolean(x: Boolean) = {
55     val av = new AnyValueMsg
56     av.setAnyValue(java.lang.Boolean.valueOf(x))
57     av
58   }
59
60   def anyValueMsgOfString(x: String) = {
61     val av = new AnyValueMsg
62     av.setAnyValue(x)
63     av
64   }
65
66   def anyValueMsgOfList(l: java.util.List[AnyValueMsg]) = {
67     val av = new AnyValueMsg
68     av.setAnyValue(l)
69     av
70   }
71
72   def newEffectiveUnitPriceMsg(
73       unitPrice: String,
74       whenOpt: Option[CronSpecTupleMsg]
75   ): EffectiveUnitPriceMsg = {
76     EffectiveUnitPriceMsg.newBuilder().
77       setUnitPrice(unitPrice).
78       setWhen(whenOpt.getOrElse(null)).
79     build()
80   }
81
82   def newEffectiveUnitPriceMsg(
83       unitPrice: Double,
84       whenOpt: Option[CronSpecTupleMsg]
85   ): EffectiveUnitPriceMsg = {
86     newEffectiveUnitPriceMsg(unitPrice.toString, whenOpt)
87   }
88
89   def newEffectivePriceTableMsg(priceOverrides: EffectiveUnitPriceMsg*) = {
90     EffectivePriceTableMsg.newBuilder().
91       setPriceOverrides(priceOverrides.asJava).
92     build()
93   }
94
95   def newSelectorValueMsg(ept: EffectivePriceTableMsg): SelectorValueMsg = {
96     SelectorValueMsg.newBuilder().
97       setSelectorValue(ept).
98     build()
99   }
100
101   def newSelectorValueMsg(map: Map[String, SelectorValueMsg]): SelectorValueMsg = {
102     SelectorValueMsg.newBuilder().
103       setSelectorValue(map.asJava).
104     build()
105   }
106
107   def newSelectorValueMsg(pairs: (String, SelectorValueMsg)*): SelectorValueMsg = {
108     SelectorValueMsg.newBuilder().
109       setSelectorValue(Map(pairs:_*).asJava).
110     build()
111   }
112
113   def newFullPriceTableMsg(perResource: (String, Map[String, SelectorValueMsg])*) = {
114     FullPriceTableMsg.newBuilder().
115       setPerResource(
116         Map((for((k, v) ← perResource) yield (k, v.asJava)):_*).asJava
117       ).
118     build()
119   }
120
121   def newRoleMappingMsg(map: Map[String, FullPriceTableMsg]): java.util.Map[String, FullPriceTableMsg] = {
122     map.asJava
123   }
124
125   def newRoleMappingMsg(pairs: (String, FullPriceTableMsg)*): java.util.Map[String, FullPriceTableMsg] = {
126     Map(pairs:_*).asJava
127   }
128
129   def newResourceTypeMsg(name: String, unit: String, chargingBehavior: String) = {
130     ResourceTypeMsg.newBuilder().
131       setName(name).
132       setUnit(unit).
133       setChargingBehaviorClass(chargingBehavior).
134     build()
135   }
136
137   def newResourceTypeMsg(model: ResourceType): ResourceTypeMsg = {
138     newResourceTypeMsg(model.name, model.unit, model.chargingBehavior)
139   }
140
141   def newResourceTypeMsgs(rts: ResourceTypeMsg*) = {
142     rts.asJava
143   }
144
145 //  def newResourceTypeMsgsMap(rts: ResourceTypeMsg*): java.util.Map[String, ResourceTypeMsg] = {
146 //    rts.map(rt ⇒ (rt.getName, rt)).toMap.asJava
147 //  }
148
149   def newResourceTypeMsgsMap(resourceTypes: Map[String, ResourceType]): java.util.Map[String, ResourceTypeMsg] = {
150     resourceTypes.map(rtt ⇒ (rtt._1, newResourceTypeMsg(rtt._2))).asJava
151   }
152
153   def newChargingBehaviorMsgs(cbs: String*) = {
154     cbs.asJava
155   }
156
157   def newBooleanDetail(name: String, value: Boolean) = {
158     (name, anyValueMsgOfBoolean(value))
159   }
160
161   def newStringDetail(name: String, value: String) = {
162     (name, anyValueMsgOfString(value))
163   }
164
165   def newDetails(details: (String, AnyValueMsg)*): DetailsModel.Type = {
166     DetailsModel.fromScalaTuples(details:_*)
167   }
168
169   def newResourceEventMsg(
170       originalID: String,
171       occurredMillis: Long,
172       receivedMillis: Long,
173       userID: String,
174       clientID: String,
175       resource: String,
176       instanceID: String,
177       value: String,
178       eventVersion: String,
179       details: DetailsModel.Type = newDetails(),
180       inStoreID: String = null
181   ) = {
182     ResourceEventMsg.newBuilder().
183       setOriginalID(originalID).
184       setOccurredMillis(occurredMillis).
185       setReceivedMillis(receivedMillis).
186       setUserID(userID).
187       setClientID(clientID).
188       setResource(resource).
189       setInstanceID(instanceID).
190       setValue(value).
191       setEventVersion(eventVersion).
192       setDetails(details).
193       setInStoreID(inStoreID).
194     build()
195   }
196
197   def newIMEventMsg(
198       originalID: String,
199       occurredMillis: Long,
200       receivedMillis: Long,
201       userID: String,
202       clientID: String,
203       isActive: Boolean,
204       role: String,
205       eventVersion: String,
206       eventType: String,
207       details: DetailsModel.Type = newDetails(),
208       inStoreID: String = null
209   ) = {
210     IMEventMsg.newBuilder().
211       setOriginalID(originalID).
212       setInStoreID(null).
213       setOccurredMillis(occurredMillis).
214       setReceivedMillis(receivedMillis).
215       setUserID(userID).
216       setClientID(clientID).
217       setIsActive(isActive).
218       setRole(role).
219       setEventVersion(eventVersion).
220       setEventType(eventType).
221       setDetails(details).
222       setInStoreID(inStoreID).
223     build()
224   }
225
226   def newWalletEntryMsg(
227       userID: String,
228       sumOfCreditsToSubtract: String,
229       oldTotalCredits: String,
230       newTotalCredits: String,
231       whenComputedMillis: Long,
232       referenceStartMillis: Long,
233       referenceStopMillis: Long,
234       billingYear: Int,
235       billingMonth: Int,
236       billingMonthDay: Int,
237       chargeslots: java.util.List[ChargeslotMsg],
238       resourceEvents: java.util.List[ResourceEventMsg],
239       resourceType: ResourceTypeMsg,
240       isSynthetic: Boolean
241   ): WalletEntryMsg = {
242     WalletEntryMsg.newBuilder().
243       setUserID(userID).
244       setSumOfCreditsToSubtract(sumOfCreditsToSubtract).
245       setOldTotalCredits(oldTotalCredits).
246       setNewTotalCredits(newTotalCredits).
247       setWhenComputedMillis(whenComputedMillis).
248       setReferenceStartMillis(referenceStartMillis).
249       setReferenceStopMillis(referenceStopMillis).
250       setBillingYear(billingYear).
251       setBillingMonth(billingMonth).
252       setBillingMonthDay(billingMonthDay).
253       setChargeslots(chargeslots).
254       setResourceEvents(resourceEvents).
255       setResourceType(resourceType).
256       setIsSynthetic(isSynthetic).
257     build()
258   }
259
260   def newResourceInstanceChargingStateMsg(
261       details: DetailsModel.Type,
262       previousEvents: java.util.List[ResourceEventMsg],
263       implicitlyIssuedStartEvents: java.util.List[ResourceEventMsg],
264       oldAccumulatingAmount: String,
265       accumulatingAmount: String,
266       previousValue: String,
267       currentValue: String,
268       clientID: String,
269       resource: String,
270       instanceID: String
271   ): ResourceInstanceChargingStateMsg = {
272
273     val msg = new ResourceInstanceChargingStateMsg
274     msg.setDetails(details)
275     msg.setPreviousEvents(previousEvents)
276     msg.setImplicitlyIssuedStartEvents(implicitlyIssuedStartEvents)
277     msg.setOldAccumulatingAmount(oldAccumulatingAmount)
278     msg.setAccumulatingAmount(accumulatingAmount)
279     msg.setPreviousValue(previousValue)
280     msg.setCurrentValue(currentValue)
281     msg.setClientID(clientID)
282     msg.setResource(resource)
283     msg.setInstanceID(instanceID)
284     msg
285   }
286
287   def newResourcesChargingStateMsg(
288     resourceName: String,
289     initialChargingDetails: DetailsModel.Type
290   ): ResourcesChargingStateMsg = {
291     val msg = new ResourcesChargingStateMsg
292     msg.setResource(resourceName)
293     msg.setDetails(initialChargingDetails)
294     msg.setStateOfResourceInstance(newJMap)
295     msg
296   }
297
298   def newEmptyUserAgreementHistoryMsg() = {
299     val msg = new UserAgreementHistoryMsg
300     msg.setAgreements(newJList[UserAgreementMsg])
301     msg
302   }
303
304   def newInitialUserAgreementHistoryMsg(
305       initialAgreement: UserAgreementMsg,
306       originalID: String = MessageHelpers.UserAgreementHistoryMsgIDGenerator.nextUID()
307   ) = {
308     val historyMsg = new UserAgreementHistoryMsg
309     historyMsg.setOriginalID(originalID)
310     MessageHelpers.insertUserAgreement(historyMsg, initialAgreement)
311     historyMsg
312   }
313
314   def newUserAgreementFromIMEventMsg(
315       imEvent: IMEventMsg,
316       agreementOriginalID: String = MessageHelpers.UserAgreementMsgIDGenerator.nextUID()
317   ) = {
318
319     val msg = new UserAgreementMsg
320
321     msg.setId(agreementOriginalID)
322     msg.setUserID(imEvent.getUserID)
323     msg.setRelatedIMEventOriginalID(imEvent.getOriginalID)
324     msg.setRole(imEvent.getRole)
325     msg.setValidFromMillis(imEvent.getOccurredMillis)
326     msg.setValidToMillis(java.lang.Long.valueOf(java.lang.Long.MAX_VALUE))
327     msg.setFullPriceTableRef(null) // get from current (= @imEvent.getOccurredMillis) policy
328     msg.setOccurredMillis(java.lang.Long.valueOf(TimeHelpers.nowMillis()))
329     msg.setRelatedIMEventMsg(imEvent)
330
331     msg
332   }
333
334   def newUserAgreementHistoryMsg(
335       userID: String,
336       originalID: String = MessageHelpers.UserAgreementHistoryMsgIDGenerator.nextUID()
337   ): UserAgreementHistoryMsg = {
338     val msg = new UserAgreementHistoryMsg
339     msg.setOriginalID(originalID)
340     msg.setUserID(userID)
341     msg.setAgreements(newJList)
342     msg
343   }
344
345   def newWalletEntriesMsg(entries: java.util.List[WalletEntryMsg] = newJList[WalletEntryMsg]) = {
346     val msg = new WalletEntriesMsg
347     msg.setEntries(entries)
348     msg
349   }
350
351   def newDummyPolicyMsgAt(millis: Long) : PolicyMsg = {
352     PolicyMsg.newBuilder().
353       setOriginalID("").
354       setInStoreID(null).
355       setParentID(null).
356       setValidFromMillis(millis).
357       setValidToMillis(Long.MaxValue).
358       setChargingBehaviors(newJList).
359       setResourceMapping(newJMap).
360       setRoleMapping(newJMap).
361       build()
362   }
363
364   /**
365    * Creates the initial (from the UserActor's perspective) user state.
366    * This may not be the very first user state ever, so we do not set `isFirst`.
367    * @param userID
368    * @param initialCredits
369    * @param occurredMillis
370    * @param originalID
371    * @return
372    */
373   def newInitialUserStateMsg(
374       userID: String,
375       initialCredits: Real,
376       occurredMillis: Long,
377       originalID: String = MessageHelpers.UserStateMsgIDGenerator.nextUID()
378   ): UserStateMsg = {
379
380     val bmi = BillingMonthInfo.fromMillis(occurredMillis)
381     val msg = new UserStateMsg
382
383     msg.setUserID(userID)
384     msg.setOccurredMillis(java.lang.Long.valueOf(occurredMillis))
385     msg.setBillingYear(java.lang.Integer.valueOf(bmi.year))
386     msg.setBillingMonth(java.lang.Integer.valueOf(bmi.month))
387     msg.setBillingMonthDay(java.lang.Integer.valueOf(bmi.day))
388     msg.setTotalCredits(Real.toMsgField(initialCredits))
389     msg.setLatestUpdateMillis(java.lang.Long.valueOf(occurredMillis))
390     msg.setInStoreID(null)
391     msg.setOriginalID(originalID)
392     msg.setStateOfResources(newJMap)
393     msg.setWalletEntries(newJList)
394     msg.setUserAgreementHistory(newUserAgreementHistoryMsg(userID))
395     msg
396   }
397 }