Flat project hierarchy
[aquarium] / src / main / scala / gr / grnet / aquarium / actor / SimpleLocalActorProvider.scala
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.actor
37
38 import com.ckkloverdos.props.Props
39 import akka.actor.ActorRef
40 import gr.grnet.aquarium.Configurable
41 import java.util.concurrent.ConcurrentHashMap
42 import gr.grnet.aquarium.util.Loggable
43
44
45 /**
46  * All actors are provided locally.
47  *
48  * @author Christos KK Loverdos <loverdos@gmail.com>.
49  */
50 class SimpleLocalActorProvider extends ActorProvider with Configurable with Loggable {
51   private[this] val actorCache = new ConcurrentHashMap[ActorRole, ActorRef]
52   private[this] var _props: Props = _
53
54   def configure(props: Props): Unit = {
55     this._props = props
56     logger.info("Configured with props: %s".format(props))
57   }
58
59   def start(): Unit = {
60     // Start all actors that need to [be started]
61     val RolesToBeStarted = SimpleLocalActorProvider.RolesToBeStarted
62     logger.info("About to start actors for %s roles: %s".format(RolesToBeStarted.size, RolesToBeStarted))
63     for((role, index) <- RolesToBeStarted.zipWithIndex) {
64       actorForRole(role)
65       logger.info("%s. Started actor for role %s".format(index + 1, role))
66     }
67
68     // Now that all actors have been started, send them some initialization code
69     val message = ActorProviderConfigured(this)
70     for(role <- RolesToBeStarted) {
71       role match {
72         case DispatcherRole ⇒
73           logger.info("Configuring %s with %s".format(DispatcherRole, message))
74           actorForRole(DispatcherRole) ! message
75         case anyOtherRole ⇒
76           logger.info("Configuring %s with %s".format(anyOtherRole, message))
77           actorForRole(anyOtherRole) ! message
78       }
79     }
80
81     logger.info("Started")
82   }
83
84   def stop(): Unit = {
85     logger.info("Stopped")
86   }
87
88   private[this] def _fromCacheOrNew(role: ActorRole): ActorRef = {
89     actorCache.get(role) match {
90       case null ⇒
91         val actorRef = akka.actor.Actor.actorOf(role.actorType).start()
92         actorCache.put(role, actorRef)
93         actorRef
94       case actorRef ⇒
95         actorRef
96     }
97   }
98
99   @throws(classOf[Exception])
100   def actorForRole(role: ActorRole, hints: Props = Props.empty) = {
101     // Currently, all actors are initialized to one instance
102     // and user actor are treated specially
103     role match {
104       case RESTRole ⇒
105         _fromCacheOrNew(RESTRole)
106       case DispatcherRole ⇒
107         _fromCacheOrNew(DispatcherRole)
108       case UserActorManagerRole ⇒
109         _fromCacheOrNew(UserActorManagerRole)
110       case UserActorRole ⇒
111         // NOTE: This always creates a new actor and is intended to be called only
112         // from internal API that can manage the created actors.
113         // E.g. UserActorProvider knows how to manage multiple user actors and properly initialize them.
114         //
115         // Note that the returned actor is not initialized!
116         akka.actor.Actor.actorOf(UserActorRole.actorType).start()
117       case _ ⇒
118         throw new Exception("Cannot create actor for role %s".format(role))
119     }
120   }
121 }
122
123 object SimpleLocalActorProvider {
124   // Always set Dispatcher at the end.
125   final val RolesToBeStarted = List(
126 //    ResourceProcessorRole,
127     RESTRole,
128     UserActorManagerRole,
129     DispatcherRole)
130
131   lazy val ActorClassByRole: Map[ActorRole, Class[_ <: AquariumActor]] =
132     RolesToBeStarted map { role ⇒
133       (role, role.actorType)
134     } toMap
135   
136   lazy val ActorRefByRole: Map[ActorRole, ActorRef] =
137     ActorClassByRole map { case (role, clazz) ⇒
138     (role, akka.actor.Actor.actorOf(clazz).start())
139   }
140 }