Also did some reorganization of actor stuff.
--- /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
+
+import com.ckkloverdos.resource._
+import com.ckkloverdos.sys.SysProp
+import com.ckkloverdos.maybe.{Failed, Just, NoVal}
+
+/**
+ * The master configurator. Responsible to load all of application configuration and provide the relevant services.
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+class MasterConf(masterConf: StreamResource) {
+}
+
+object MasterConf {
+ val MasterConfName = "aquarium.properties"
+
+ /**
+ * Current directory resource context.
+ * Normally this should be the application installation directory.
+ *
+ * It takes priority over `ClasspathBaseResourceContext`.
+ */
+ val AppBaseResourceContext = new FileStreamResourceContext(".")
+
+ /**
+ * The venerable /etc resource context
+ */
+ val SlashEtcResourceContext = new FileStreamResourceContext("/etc")
+
+ /**
+ * Class loader resource context.
+ * This has the lowest priority.
+ */
+ val ClasspathBaseResourceContext = new ClassLoaderStreamResourceContext(Thread.currentThread().getContextClassLoader)
+
+ /**
+ * Use this property to override the place where aquarium configuration resides.
+ *
+ * The value of this property is a folder that defines the highest-priority resource context.
+ */
+ val ConfBaseFolderSysProp = SysProp("aquarium.conf.base.folder")
+
+ /**
+ * The default resource context used in the application. If you need toi
+ */
+ lazy val MasterResourceContext = {
+ val rc0 = ClasspathBaseResourceContext
+ val rc1 = AppBaseResourceContext
+ val rc2 = SlashEtcResourceContext
+ val basicContext = new CompositeStreamResourceContext(NoVal, rc2, rc1, rc0)
+
+ ConfBaseFolderSysProp.value match {
+ case Just(value) ⇒
+ // We have a system override for the configuration location
+ new CompositeStreamResourceContext(Just(basicContext), new FileStreamResourceContext(value))
+ case NoVal ⇒
+ basicContext
+ case Failed(e, m) ⇒
+ throw new RuntimeException(m , e)
+ }
+ }
+
+ lazy val MasterConfResource = {
+ val maybeMCResource = MasterResourceContext getResource MasterConfName
+ maybeMCResource match {
+ case Just(masterConfResource) ⇒
+ masterConfResource
+ case NoVal ⇒
+ throw new RuntimeException("Could not find master configuration file: %s".format(MasterConfName))
+ case Failed(e, m) ⇒
+ throw new RuntimeException(m, e)
+ }
+ }
+
+ lazy val MasterConf = new MasterConf(MasterConfResource)
+}
\ No newline at end of file
--- /dev/null
+package gr.grnet.aquarium.actor
+
+/*
+ * 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.
+ */
+
+sealed abstract class ActorRole(val role: String)
+
+/**
+ * The generic router/dispatcher.
+ */
+case object DispatcherRole extends ActorRole("DispatcherRole")
+
+/**
+ * Processes user-related resource events.
+ */
+case object ResourceProcessorRole extends ActorRole("ResourceProcessorRole")
* or implied, of GRNET S.A.
*/
-package gr.grnet.aquarium.processor.actor
+package gr.grnet.aquarium
+package actor
-import AquariumActorRoles.AquariumActorRole
import akka.actor.Actor
/**
* @author Christos KK Loverdos <loverdos@gmail.com>.
*/
trait AquariumActor extends Actor {
- def role: AquariumActorRole
+ def role: ActorRole
}
\ No newline at end of file
import gr.grnet.aquarium.logic.events.ResourceEvent
import akka.actor.ActorRef
+import gr.grnet.aquarium.actor.{DispatcherRole, AquariumActor}
/**
*
* @author Christos KK Loverdos <loverdos@gmail.com>.
*/
class AquariumDispatcher extends AquariumActor {
- def role = AquariumActorRoles.Dispatcher
+ def role = DispatcherRole
def resourceEventProcessor: ActorRef =
AquariumActorFactory.get.makeResourceEventProcessor
*
* @author Christos KK Loverdos <loverdos@gmail.com>.
*/
-object AquariumActorRoles {
- sealed abstract class AquariumActorRole(val role: String)
-
- /**
- * The generic router/dispatcher.
- */
- case object Dispatcher extends AquariumActorRole("Dispatcher")
-
-
- /**
- * Processes user-related resource events.
- */
- case object ResourceProcessor extends AquariumActorRole("ResourceProcessor")
-}
\ No newline at end of file
+object Constants {
+ val RemoteHost = "localhost"
+ val RemotePort = 2552
+ val LocalHost = "localhost"
+ val LocalPort = 2551
+ val ActorNameEcho = "echo"
+ val ActorNameSilent = "silent"
+}
package gr.grnet.aquarium.processor.actor
import gr.grnet.aquarium.logic.events.ResourceEvent
+
import akka.event.EventHandler
+import gr.grnet.aquarium.actor.{ResourceProcessorRole, AquariumActor}
/**
*
* @author Christos KK Loverdos <loverdos@gmail.com>.
*/
class ResourceEventProcessor extends AquariumActor with ReflectiveAquariumActor {
- def role = AquariumActorRoles.ResourceProcessor
+ def role = ResourceProcessorRole
def knownMessageTypes = List(classOf[ResourceEvent])
package gr.grnet.aquarium.rest.akka.service
-import org.slf4j.LoggerFactory
-import cc.spray.can.HttpMethods.GET
+import cc.spray.can.HttpMethods.{GET, POST}
import cc.spray.can._
import akka.actor.Actor
import gr.grnet.aquarium.util.Loggable
import net.liftweb.json.{JsonAST, Printer}
/**
+ * Spray-based REST service. This is the outer-world's interface to Aquarium functionality.
*
* @author Christos KK Loverdos <loverdos@gmail.com>.
*/
class AquariumRESTService(_id: String = "spray-root-service", version: String) extends Actor with Loggable {
self.id = _id
-// private[this] def jsonResponseOK(body: JValue, pretty: Boolean = false): HttpResponse = {
-// HttpResponse(
-// 200,
-// HttpHeader("Content-type", "application/json;charset=utf-8") :: Nil,
-// if(pretty) {
-// Printer.pretty(JsonAST.render(body)).getB
-// } else {
-// bo
-// }
-// )
-// }
- protected def receive = {
- case RequestContext(HttpRequest(GET, "/", _, _, _), _, responder) =>
- responder.complete(index)
+ private def jsonResponse200(body: JValue, pretty: Boolean = false): HttpResponse = {
+ val stringBody = Printer.pretty(JsonAST.render(body))
+ stringResponse200(stringBody, "application/json")
+ }
+
+ private def stringResponse(status: Int, stringBody: String, contentType: String = "application/json"): HttpResponse = {
+ HttpResponse(
+ status,
+ HttpHeader("Content-type", "%s;charset=utf-8".format(contentType)) :: Nil,
+ stringBody.getBytes("UTF-8")
+ )
+ }
+
+ private def stringResponse200(stringBody: String, contentType: String = "application/json"): HttpResponse = {
+ stringResponse(200, stringBody, contentType)
+ }
+ protected def receive = {
case RequestContext(HttpRequest(GET, "/ping", _, _, _), _, responder) =>
- responder.complete(response("PONG!"))
+ responder.complete(stringResponse200("{pong: %s}".format(System.currentTimeMillis())))
case RequestContext(HttpRequest(GET, "/stats", _, _, _), _, responder) => {
(serverActor ? GetStats).mapTo[Stats].onComplete {
future =>
future.value.get match {
case Right(stats) => responder.complete {
- response {
+ stringResponse200 (
"Uptime : " + (stats.uptime / 1000.0) + " sec\n" +
"Requests dispatched : " + stats.requestsDispatched + '\n' +
"Requests timed out : " + stats.requestsTimedOut + '\n' +
"Requests open : " + stats.requestsOpen + '\n' +
"Open connections : " + stats.connectionsOpen + '\n'
- }
+ )
}
- case Left(ex) => responder.complete(response("Couldn't get server stats due to " + ex, status = 500))
+ case Left(ex) => responder.complete(stringResponse(500, "Couldn't get server stats due to " + ex, "text/plain"))
}
}
}
+ case RequestContext(HttpRequest(POST, "/events", _, _, _), _, responder) =>
+ // POST events here.
+ // FIXME: implement
+ responder.complete(stringResponse200("{pong: %s}".format(System.currentTimeMillis())))
+
case RequestContext(HttpRequest(_, _, _, _, _), _, responder) =>
- responder.complete(response("Unknown resource!", 404))
+ responder.complete(stringResponse(404, "Unknown resource!", "text/plain"))
case Timeout(method, uri, _, _, _, complete) => complete {
HttpResponse(status = 500).withBody("The " + method + " request to '" + uri + "' has timed out...")
val defaultHeaders = List(HttpHeader("Content-Type", "text/plain"))
lazy val serverActor = Actor.registry.actorsFor("spray-can-server").head
-
- def response(msg: String, status: Int = 200) = HttpResponse(status, defaultHeaders, msg.getBytes("ISO-8859-1"))
-
- lazy val index = HttpResponse(
- headers = List(HttpHeader("Content-Type", "text/html")),
- body =
- <html>
- <body>
- <h1>Say hello to
- <i>spray-can</i>
- !</h1>
- <p>Defined resources:</p>
- <ul>
- <li>
- <a href="/ping">/ping</a>
- </li>
- <li>
- <a href="/stats">/stats</a>
- </li>
- </ul>
- </body>
- </html>.toString.getBytes("UTF-8")
- )
}
\ No newline at end of file
--- /dev/null
+version=0.0.2-SNAPSHOT
+
--- /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
+
+import org.junit.Test
+import org.junit.Assert._
+import org.junit.Assume.assumeTrue
+
+/**
+ *
+ * @author Christos KK Loverdos <loverdos@gmail.com>.
+ */
+class MasterConfTest {
+ @Test
+ def testExists: Unit = {
+ val rc = MasterConf.MasterConfResource
+ assertTrue(MasterConf.MasterConfName, rc.exists)
+ }
+}
\ No newline at end of file
//import akka.actor.Actor.
-object Constants {
- val RemoteHost = "localhost"
- val RemotePort = 2552
- val LocalHost = "localhost"
- val LocalPort = 2551
- val ActorNameEcho = "echo"
- val ActorNameSilent = "silent"
-}
class EchoActor extends Actor {
def receive = {
}
}
-abstract class ActorProxy(name: String, host: String = Constants.RemoteHost, port: Int = Constants.RemotePort) extends Actor {
- val remote = Actor.remote.actorFor(name, host, port)
-
- def receive = {
- case message =>
- remote ! message
- }
-}
-
class EchoProxy extends ActorProxy("echo")
class SilentProxy extends ActorProxy("silent")
val lib_yaml = "org.yaml" % "snakeyaml" % "1.9" withSources()
val lib_jcrontab = "com.kenai.crontab-parser" % "crontab-parser" % "1.0.1" withSources()
val lib_xstream = "com.thoughtworks.xstream" % "xstream" % "1.4.1" withSources()
- val lib_rabbit = "com.rabbitmq" % "amqp-client" % "2.7.0" withSources()
+ val lib_rabbit = "com.rabbitmq" % "amqp-client" % "2.5.0" withSources()
val lib_mongo = "org.mongodb" % "mongo-java-driver" % "2.7.2" withSources()
//val lib_casbah = "com.mongodb.casbah" % "casbah-core_2.9.1" % "2.1.5-1" withSources()
- val lib_akka_actor = "se.scalablesolutions.akka" % "akka-actor" % "1.3-RC1" withSources()
- val lib_akka_remote = "se.scalablesolutions.akka" % "akka-remote" % "1.3-RC1" withSources()
- val lib_akka_test = "se.scalablesolutions.akka" % "akka-testkit" % "1.3-RC1" % "test" withSources()
+ val lib_akka_actor = "se.scalablesolutions.akka" % "akka-actor" % "1.3-RC2" withSources()
+ val lib_akka_remote = "se.scalablesolutions.akka" % "akka-remote" % "1.3-RC2" withSources()
+ val lib_akka_test = "se.scalablesolutions.akka" % "akka-testkit" % "1.3-RC2" % "test" withSources()
+ val lib_akka_amqp = "se.scalablesolutions.akka" % "akka-amqp" % "1.3-RC2" withSources()
val lib_javaxrs = "javax.ws.rs" % "jsr311-api" % "1.1.1" withSources()
val lib_spray_can = "cc.spray.can" % "spray-can" % "0.9.2-SNAPSHOT" withSources()