# DO NOT TOUCH the following, unless you know what you are doing
# Actor subsystem
actor.provider.class=gr.grnet.aquarium.actor.SimpleLocalActorProvider
+# Class that initializes the REST service
+rest.service.class=gr.grnet.aquarium.rest.actor.RESTActorService
# Comma separated list of exchanges known to aquarium
amqp.exchanges=aquarium
import com.ckkloverdos.props.Props
import com.ckkloverdos.maybe.{Maybe, Failed, Just, NoVal}
import com.ckkloverdos.convert.Converters.{DefaultConverters => TheDefaultConverters}
+import rest.RESTService
/**
* The master configurator. Responsible to load all of application configuration and provide the relevant services.
class MasterConf(val props: Props) {
import MasterConf.Keys
- private[this] val _actorProvider: ActorProvider = {
- val className = props.getEx(Keys.actor_provider_class)
- val actorProvider = defaultClassLoader.loadClass(className).newInstance().asInstanceOf[ActorProvider]
-
- actorProvider match {
+ private[this] def newInstance[C : Manifest](className: String): C = {
+ val c = defaultClassLoader.loadClass(className).newInstance().asInstanceOf[C]
+ c match {
case configurable: Configurable ⇒
configurable configure props
+ c
+ case _ ⇒
+ c
}
+ }
- actorProvider
+ private[this] val _actorProvider: ActorProvider = {
+ newInstance[ActorProvider](props.getEx(Keys.actor_provider_class))
+ }
+
+ private[this] val _restService: RESTService = {
+ newInstance[RESTService](props.getEx(Keys.rest_service_class))
}
def get(prop: String): String =
}
def defaultClassLoader = Thread.currentThread().getContextClassLoader
+
+ def startServices(): Unit = {
+ _actorProvider.start()
+ _restService.start()
+ }
+
+ def stopServices(): Unit = {
+ _restService.stop()
+ _actorProvider.stop()
+
+// akka.actor.Actor.registry.shutdownAll()
+ }
+
+ def stopServicesWithDelay(millis: Long) {
+ Thread sleep millis
+ stopServices()
+ }
def actorProvider = _actorProvider
}
final val actor_provider_class = "actor.provider.class"
/**
+ * The class that initializes the REST service
+ */
+ final val rest_service_class = "rest.service.class"
+
+ /**
* Comma separated list of amqp servers running in active-active
* configuration.
*/
*/
@throws(classOf[Exception])
def actorForRole(role: ActorRole, hints: Props = Props.empty): ActorRef
+
+ def start(): Unit
+
+ def stop(): Unit
}
\ No newline at end of file
*/
class SimpleLocalActorProvider extends ActorProvider with Configurable {
def configure(props: Props): Unit = {
+ }
+
+ def start(): Unit = {
+ for(role <- SimpleLocalActorProvider.KnownRoles) {
+ actorForRole(role)
+ }
+ }
+ def stop(): Unit = {
}
@throws(classOf[Exception])
--- /dev/null
+/*
+ * Copyright 2011 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ */
+
+package gr.grnet.aquarium.rest
+
+import gr.grnet.aquarium.Configurable
+
+/**
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+trait RESTService {
+ def start(): Unit
+ def stop(): Unit
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2011 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ */
+
+package gr.grnet.aquarium.rest
+package actor
+
+import gr.grnet.aquarium.MasterConf
+import gr.grnet.aquarium.actor.RESTRole
+import _root_.akka.actor._
+import cc.spray.can.{ClientConfig, HttpClient, ServerConfig, HttpServer}
+
+/**
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+class RESTActorService extends RESTService {
+ private[this] var _port: Int = 8080
+ private[this] var _restActor: ActorRef = _
+ private[this] var _serverActor: ActorRef = _
+ private[this] var _clientActor: ActorRef = _
+
+ def start(): Unit = {
+ val mc = MasterConf.MasterConf
+ this._port = mc.props.getInt(MasterConf.Keys.rest_port).getOr(this._port)
+ this._restActor = mc.actorProvider.actorForRole(RESTRole)
+ // Start Spray subsystem
+ val serverConfig = ServerConfig(port = _port)
+ val clientConfig = ClientConfig()
+ this._serverActor = Actor.actorOf(new HttpServer(serverConfig)).start()
+ this._clientActor = Actor.actorOf(new HttpClient(clientConfig)).start()
+ }
+
+ def stop(): Unit = {
+ this._serverActor ! PoisonPill
+ this._clientActor ! PoisonPill
+ }
+}
\ No newline at end of file
*/
class RESTActorTest {
@Test
- def testOneCall: Unit = {
+ def testPing: Unit = {
// Initialize configuration subsystem
val mc = MasterConf.MasterConf
+ mc.startServices()
val port = mc.props.getInt(MasterConf.Keys.rest_port).getOr(8080)
- // Initialize REST actor
- val rest = mc.actorProvider.actorForRole(RESTRole)
- // Initialize spray underlying server
- val server = Actor.actorOf(new SprayHttpServer()).start()
- val client = Actor.actorOf(new SprayHttpClient()).start()
val dialog = SprayHttpDialog("localhost", port)
val pingReq = HttpRequest(method = GET, uri = "/ping", headers = HttpHeader("Content-Type", "text/plain; charset=UTF-8")::Nil)
fail("Got nothing")
}
}
-
- Thread.sleep(3000)
- server ! PoisonPill
- client ! PoisonPill
- Actor.registry.shutdownAll()
+
+ mc.stopServicesWithDelay(1000)
}
}
\ No newline at end of file