2 * Copyright 2011 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.user.actor
38 import gr.grnet.aquarium.user.UserState
39 import gr.grnet.aquarium.util.Loggable
40 import scala.PartialFunction
41 import gr.grnet.aquarium.actor._
42 import com.ckkloverdos.maybe.Maybe
43 import gr.grnet.aquarium.Configurator
44 import gr.grnet.aquarium.processor.actor.{UserResponseGetState, UserRequestGetState, UserResponseGetBalance, UserRequestGetBalance}
49 * @author Christos KK Loverdos <loverdos@gmail.com>
52 class UserActor extends AquariumActor with Loggable {
54 private[this] var _userId: String = _
56 private[this] var _isInitialized: Boolean = false
58 private[this] var _userState: UserState = _
60 private[this] var _actorProvider: ActorProvider = _
62 private[this] var _timestampTheshold: Long = _
64 def role = UserActorRole
66 protected def receive: Receive = {
70 case m @ AquariumPropertiesLoaded(props) ⇒
71 this._timestampTheshold = props.getLong(Configurator.Keys.user_state_timestamp_threshold).getOr(10000)
72 logger.info("Setup my timestampTheshold = %s".format(this._timestampTheshold))
74 case m @ UserActorInitWithUserId(userId) ⇒
76 this._isInitialized = true
77 // TODO: query DB etc to get internal state
78 logger.info("Setup my userId = %s".format(userId))
80 case m @ ActorProviderConfigured(actorProvider) ⇒
81 this._actorProvider = actorProvider
82 logger.info("Configured %s with %s".format(this, m))
84 case m @ UserRequestGetBalance(userId, timestamp) ⇒
85 if(this._userId != userId) {
86 logger.error("Received %s but my userId = %s".format(m, this._userId))
87 // TODO: throw an exception here
89 // This is the big party.
90 // Get the user state, if it exists and make sure it is not stale.
92 // Do we have a user state?
93 if(_userState ne null) {
94 // Yep, we do. See what there is inside it.
95 val credits = _userState.credits
96 val creditsTimestamp = credits.snapshotTime
98 // Check if data is stale
99 if(creditsTimestamp + _timestampTheshold > timestamp) {
101 self reply UserResponseGetBalance(userId, credits.data)
103 // Yep, data is stale and must recompute balance
105 logger.error("FIXME: Should have computed a new value for %s".format(credits))
106 self reply UserResponseGetBalance(userId, credits.data)
109 // Nope. No user state exists. Must reproduce one
111 logger.error("FIXME: Should have computed the user state for userId = %s".format(userId))
112 self reply UserResponseGetBalance(userId, Maybe(userId.toDouble).getOr(10.5))
116 case m @ UserRequestGetState(userId, timestamp) ⇒
117 if(this._userId != userId) {
118 logger.error("Received %s but my userId = %s".format(m, this._userId))
119 // TODO: throw an exception here
122 logger.error("FIXME: Should have properly computed the user state")
123 self reply UserResponseGetState(userId, this._userState)