2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
36 package gr.grnet.aquarium.computation.reason
38 import gr.grnet.aquarium.computation.BillingMonthInfo
39 import gr.grnet.aquarium.event.model.im.IMEventModel
40 import gr.grnet.aquarium.util.shortClassNameOf
43 * Provides information explaining the reason Aquarium calculated a new [[gr.grnet.aquarium.computation.UserState]].
45 case class UserStateChangeReason(
46 parentReason: Option[UserStateChangeReason],
47 billingMonthInfo: Option[BillingMonthInfo],
48 details: Map[String, Any]
52 details.contains(UserStateChangeReason.Names.`type`),
53 "No type present in the details of %s".format(shortClassNameOf(this))
56 private[this] def booleanFromDetails(name: String, default: Boolean) = {
57 details.get(name) match {
58 case Some(value: Boolean) ⇒
67 * Return `true` if the result of the calculation should be stored back to the
68 * [[gr.grnet.aquarium.store.UserStateStore]].
71 def shouldStoreUserState: Boolean =
72 booleanFromDetails(UserStateChangeReason.Names.shouldStoreUserState, false)
74 def shouldStoreCalculatedWalletEntries: Boolean =
75 booleanFromDetails(UserStateChangeReason.Names.shouldStoreCalculatedWalletEntries, false)
77 def calculateCreditsForImplicitlyTerminated: Boolean =
78 booleanFromDetails(UserStateChangeReason.Names.calculateCreditsForImplicitlyTerminated, false)
80 def forBillingMonthInfo(bmi: BillingMonthInfo) = {
82 parentReason = Some(this),
83 billingMonthInfo = Some(bmi)
87 def `type`: String = {
88 // This must be always present
89 details(UserStateChangeReason.Names.`type`).asInstanceOf[String]
93 object UserStateChangeReason {
95 final val `type` = "type"
97 final val imEvent = "imEvent"
98 final val forWhenMillis = "forWhenMillis"
100 final val shouldStoreUserState = "shouldStoreUserState"
101 final val shouldStoreCalculatedWalletEntries = "shouldStoreCalculatedWalletEntries"
102 final val calculateCreditsForImplicitlyTerminated = "calculateCreditsForImplicitlyTerminated"
106 sealed trait UserStateChangeReason_ {
107 def originalReason: UserStateChangeReason_
109 * Return `true` if the result of the calculation should be stored back to the
110 * [[gr.grnet.aquarium.store.UserStateStore]].
113 def shouldStoreUserState: Boolean
115 def shouldStoreCalculatedWalletEntries: Boolean
117 def forPreviousBillingMonth: UserStateChangeReason_
119 def calculateCreditsForImplicitlyTerminated: Boolean
121 def code: UserStateChangeReasonCodes.ChangeReasonCode
124 object InitialUserStateSetup {
125 def `type` = "InitialUserStateSetup"
128 * When the user state is initially set up.
130 def apply(parentReason: Option[UserStateChangeReason]) = {
131 UserStateChangeReason(
135 UserStateChangeReason.Names.`type` -> `type`,
136 UserStateChangeReason.Names.shouldStoreUserState -> true
142 object InitialUserActorSetup {
143 def `type` = "InitialUserActorSetup"
146 * When the user processing unit (actor) is initially set up.
149 UserStateChangeReason(
153 UserStateChangeReason.Names.`type` -> `type`,
154 UserStateChangeReason.Names.shouldStoreUserState -> true
160 object NoSpecificChangeReason {
161 def `type` = "NoSpecificChangeReason"
164 * A calculation made for no specific reason. Can be for testing, for example.
167 UserStateChangeReason(
171 UserStateChangeReason.Names.`type` -> `type`
177 object MonthlyBillingCalculation {
178 def `type` = "MonthlyBillingCalculation"
181 * An authoritative calculation for the billing period.
183 def apply(parentReason: UserStateChangeReason, billingMongthInfo: BillingMonthInfo) = {
184 UserStateChangeReason(
186 Some(billingMongthInfo),
188 UserStateChangeReason.Names.`type` -> `type`,
189 UserStateChangeReason.Names.shouldStoreUserState -> true,
190 UserStateChangeReason.Names.shouldStoreCalculatedWalletEntries -> true,
191 UserStateChangeReason.Names.calculateCreditsForImplicitlyTerminated -> true
197 object RealtimeBillingCalculation {
198 def `type` = "RealtimeBillingCalculation"
201 * Used for the real-time billing calculation.
203 def apply(parentReason: Option[UserStateChangeReason], forWhenMillis: Long) = {
204 UserStateChangeReason(
208 UserStateChangeReason.Names.`type` -> `type`,
209 UserStateChangeReason.Names.forWhenMillis -> forWhenMillis
215 object IMEventArrival {
216 def `type` = "IMEventArrival"
218 def apply(imEvent: IMEventModel) = {
219 UserStateChangeReason(
223 UserStateChangeReason.Names.`type` -> `type`,
224 UserStateChangeReason.Names.imEvent -> imEvent,
225 UserStateChangeReason.Names.shouldStoreUserState -> true