Configure aquarium when creating the user actor
[aquarium] / src / main / scala / gr / grnet / aquarium / service / SimpleLocalRoleableActorProviderService.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.service
37
38 import com.ckkloverdos.props.Props
39 import akka.actor.ActorRef
40 import gr.grnet.aquarium.{AquariumAwareSkeleton, Configurable}
41 import java.util.concurrent.ConcurrentHashMap
42 import gr.grnet.aquarium.util.Loggable
43 import gr.grnet.aquarium.actor.message.config.{AquariumPropertiesLoaded, ActorProviderConfigured}
44 import gr.grnet.aquarium.actor._
45 import gr.grnet.aquarium.service.event.AquariumCreatedEvent
46
47 /**
48  * All actors are provided locally.
49  *
50  * @author Christos KK Loverdos <loverdos@gmail.com>.
51  */
52 class SimpleLocalRoleableActorProviderService
53   extends RoleableActorProviderService
54      with AquariumAwareSkeleton
55      with Configurable
56      with Loggable {
57
58   private[this] val actorCache = new ConcurrentHashMap[ActorRole, ActorRef]
59   @volatile private[this] var _props: Props = _
60
61   def propertyPrefix = None
62
63   def configure(props: Props): Unit = {
64     this._props = props
65   }
66
67   def start(): Unit = {
68     // Start and configure actors
69     import SimpleLocalRoleableActorProviderService.RolesToBeStarted
70
71     for(role <- RolesToBeStarted) {
72       actorForRole(role)
73     }
74   }
75
76   def stop(): Unit = {
77   }
78
79   private[this] def _newActor(role: ActorRole): ActorRef = {
80     val actorFactory = (_class: Class[_ <: RoleableActor]) ⇒ {
81       val actor = aquarium.newInstance(_class, _class.getName)
82       actor.awareOfAquariumEx(AquariumCreatedEvent(aquarium))
83       actor
84     }
85
86     val actorRef = akka.actor.Actor.actorOf(actorFactory(role.actorType)).start()
87
88     val propsMsg = AquariumPropertiesLoaded(this._props)
89     if(role.canHandleConfigurationMessage(propsMsg)) {
90       actorRef ! propsMsg
91     }
92
93     val providerMsg = ActorProviderConfigured(this)
94     if(role.canHandleConfigurationMessage(providerMsg)) {
95       actorRef ! providerMsg
96     }
97
98     actorRef
99   }
100
101   private[this] def _fromCacheOrNew(role: ActorRole): ActorRef = synchronized {
102     actorCache.get(role) match {
103       case null ⇒
104         val actorRef = _newActor(role)
105         actorCache.put(role, actorRef)
106         actorRef
107       case actorRef ⇒
108         actorRef
109     }
110   }
111
112   @throws(classOf[Exception])
113   def actorForRole(role: ActorRole, hints: Props = Props.empty) = synchronized {
114     if(role.isCacheable) {
115       _fromCacheOrNew(role)
116     } else {
117       _newActor(role)
118     }
119   }
120
121   override def toString = gr.grnet.aquarium.util.shortClassNameOf(this)
122 }
123
124 object SimpleLocalRoleableActorProviderService {
125   // Always set Router at the end.
126   // We could definitely use some automatic dependency sorting here (topological sorting anyone?)
127   final val RolesToBeStarted = List(
128     PingerRole,
129     RouterRole)
130
131   lazy val ActorClassByRole: Map[ActorRole, Class[_ <: RoleableActor]] =
132     RolesToBeStarted map {
133       role ⇒
134         (role, role.actorType)
135     } toMap
136
137   lazy val ActorRefByRole: Map[ActorRole, ActorRef] =
138     ActorClassByRole map {
139       case (role, clazz) ⇒
140         (role, akka.actor.Actor.actorOf(clazz).start())
141     }
142 }