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
38 import actor.{DispatcherRole, ActorProvider}
39 import com.ckkloverdos.resource._
40 import com.ckkloverdos.sys.SysProp
41 import com.ckkloverdos.props.Props
42 import com.ckkloverdos.maybe.{Maybe, Failed, Just, NoVal}
43 import com.ckkloverdos.convert.Converters.{DefaultConverters => TheDefaultConverters}
44 import processor.actor.ConfigureDispatcher
45 import rest.RESTService
46 import store.{EventStore, UserStore}
50 * The master configurator. Responsible to load all of application configuration and provide the relevant services.
52 * @author Christos KK Loverdos <loverdos@gmail.com>.
54 class MasterConf(val props: Props) extends Loggable {
55 import MasterConf.Keys
57 private[this] def newInstance[C : Manifest](className: String): C = {
58 val c = defaultClassLoader.loadClass(className).newInstance().asInstanceOf[C]
60 case configurable: MasterConfigurable ⇒
61 configurable configure this
63 case configurable: Configurable ⇒
64 configurable configure props
71 private[this] val _actorProvider: ActorProvider = {
72 val instance = newInstance[ActorProvider](props.getEx(Keys.actor_provider_class))
73 logger.info("Loaded ActorProvider: %s".format(instance.getClass))
77 private[this] val _restService: RESTService = {
78 val instance = newInstance[RESTService](props.getEx(Keys.rest_service_class))
79 logger.info("Loaded RESTService: %s".format(instance.getClass))
83 private[this] val _userStore: UserStore = {
84 val instance = newInstance[UserStore](props.getEx(Keys.user_store_class))
85 logger.info("Loaded UserStore: %s".format(instance.getClass))
89 private[this] val _eventStore: EventStore = {
90 val instance = newInstance[EventStore](props.getEx(Keys.event_store_class))
91 logger.info("Loaded EventStore: %s".format(instance.getClass))
95 def get(prop: String): String =
96 props.get(prop) match {
101 def defaultClassLoader = Thread.currentThread().getContextClassLoader
103 def startServices(): Unit = {
105 _actorProvider.start()
107 _actorProvider.actorForRole(DispatcherRole) ! ConfigureDispatcher(this)
110 def stopServices(): Unit = {
112 _actorProvider.stop()
114 // akka.actor.Actor.registry.shutdownAll()
117 def stopServicesWithDelay(millis: Long) {
122 def actorProvider = _actorProvider
124 def userStore = _userStore
126 def eventStore = _eventStore
130 implicit val DefaultConverters = TheDefaultConverters
132 val MasterConfName = "aquarium.properties"
135 * Current directory resource context.
136 * Normally this should be the application installation directory.
138 * It takes priority over `ClasspathBaseResourceContext`.
140 val AppBaseResourceContext = new FileStreamResourceContext(".")
143 * The venerable /etc resource context
145 val SlashEtcResourceContext = new FileStreamResourceContext("/etc")
148 * Class loader resource context.
149 * This has the lowest priority.
151 val ClasspathBaseResourceContext = new ClassLoaderStreamResourceContext(Thread.currentThread().getContextClassLoader)
154 * Use this property to override the place where aquarium configuration resides.
156 * The value of this property is a folder that defines the highest-priority resource context.
158 val ConfBaseFolderSysProp = SysProp("aquarium.conf.base.folder")
161 * The resource context used in the application.
163 lazy val MasterResourceContext = {
164 val rc0 = ClasspathBaseResourceContext
165 val rc1 = AppBaseResourceContext
166 val rc2 = SlashEtcResourceContext
167 val basicContext = new CompositeStreamResourceContext(NoVal, rc2, rc1, rc0)
169 ConfBaseFolderSysProp.value match {
171 // We have a system override for the configuration location
172 new CompositeStreamResourceContext(Just(basicContext), new FileStreamResourceContext(value))
176 throw new RuntimeException(m , e)
180 lazy val MasterConfResource = {
181 val maybeMCResource = MasterResourceContext getResource MasterConfName
182 maybeMCResource match {
183 case Just(masterConfResource) ⇒
186 throw new RuntimeException("Could not find master configuration file: %s".format(MasterConfName))
188 throw new RuntimeException(m, e)
192 lazy val MasterConfProps = {
193 val maybeProps = Props apply MasterConfResource
198 throw new RuntimeException("Could not load master configuration file: %s".format(MasterConfName))
200 throw new RuntimeException(m, e)
204 lazy val MasterConf = {
205 Maybe(new MasterConf(MasterConfProps)) match {
206 case Just(masterConf) ⇒
209 throw new RuntimeException("Could not initialize master configuration file: %s".format(MasterConfName))
211 throw new RuntimeException(m, e)
216 * Defines the names of all the known keys inside the master properties file.
220 * The Aquarium version. Will be reported in any due occasion.
222 final val version = "version"
225 * The fully qualified name of the class that implements the `ActorProvider`.
226 * Will be instantiated reflectively and should have a public default constructor.
228 final val actor_provider_class = "actor.provider.class"
231 * The class that initializes the REST service
233 final val rest_service_class = "rest.service.class"
236 * The class that implements the User store
238 final val user_store_class = "user.store.class"
241 * The class that implements the event store
243 final val event_store_class = "event.store.class"
246 * Comma separated list of amqp servers running in active-active
249 final val amqp_servers = "amqp.servers"
252 * Comma separated list of amqp servers running in active-active
255 final val amqp_port = "amqp.port"
258 * User name for connecting with the AMQP server
260 final val amqp_username = "amqp.username"
263 * Passwd for connecting with the AMQP server
265 final val amqp_password = "amqp.passwd"
268 * Virtual host on the AMQP server
270 final val amqp_vhost = "amqp.vhost"
273 * Comma separated list of exchanges known to aquarium
275 final val amqp_exchanges = "amqp.exchanges"
278 * REST service listening port.
282 final val rest_port = "rest.port"
285 * Provider for persistence services
287 final val persistence_provider = "persistence.provider"
290 * Hostname for the persistence service
292 final val persistence_host = "persistence.host"
295 * Username for connecting to the persistence service
297 final val persistence_username = "persistence.username"
300 * Password for connecting to the persistence service
302 final val persistence_password = "persistence.password"
305 * Password for connecting to the persistence service
307 final val persistence_port = "persistence.port"
310 * The DB schema to use
312 final val persistence_db = "persistence.db"