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.rest.akka.service
39 import cc.spray.can.HttpClient._
41 import cc.spray.can.HttpMethods.GET
42 import gr.grnet.aquarium.util.Loggable
43 import org.junit.Assume._
44 import gr.grnet.aquarium.LogicTestsAssumptions
46 import akka.actor.{Actor, PoisonPill}
47 import org.slf4j.LoggerFactory
50 * This class is heavily based on the Spray samples.
51 * Copyright is what copyright Spray has.
53 class SprayPingService(_id: String = "spray-root-service") extends Actor {
54 private[this] val logger = LoggerFactory.getLogger(getClass)
58 protected def receive = {
59 case RequestContext(HttpRequest(GET, "/", _, _, _), _, responder) =>
60 responder.complete(index)
62 case RequestContext(HttpRequest(GET, "/ping", _, _, _), _, responder) =>
63 responder.complete(response("PONG!"))
65 case RequestContext(HttpRequest(GET, "/stats", _, _, _), _, responder) => {
66 (serverActor ? GetStats).mapTo[Stats].onComplete {
68 future.value.get match {
69 case Right(stats) => responder.complete {
71 "Uptime : " + (stats.uptime / 1000.0) + " sec\n" +
72 "Requests dispatched : " + stats.requestsDispatched + '\n' +
73 "Requests timed out : " + stats.requestsTimedOut + '\n' +
74 "Requests open : " + stats.requestsOpen + '\n' +
75 "Open connections : " + stats.connectionsOpen + '\n'
78 case Left(ex) => responder.complete(response("Couldn't get server stats due to " + ex, status = 500))
83 case RequestContext(HttpRequest(_, _, _, _, _), _, responder) =>
84 responder.complete(response("Unknown resource!", 404))
86 case Timeout(method, uri, _, _, _, complete) => complete {
87 HttpResponse(status = 500).withBody("The " + method + " request to '" + uri + "' has timed out...")
91 ////////////// helpers //////////////
93 val defaultHeaders = List(HttpHeader("Content-Type", "text/plain"))
95 lazy val serverActor = Actor.registry.actorsFor("spray-can-server").head
97 def response(msg: String, status: Int = 200) = HttpResponse(status, defaultHeaders, msg.getBytes("ISO-8859-1"))
99 lazy val index = HttpResponse(
100 headers = List(HttpHeader("Content-Type", "text/html")),
107 <p>Defined resources:</p>
110 <a href="/ping">/ping</a>
113 <a href="/stats">/stats</a>
117 </html>.toString.getBytes("UTF-8")
123 * @author Christos KK Loverdos <loverdos@gmail.com>.
125 class SprayPingServiceTest extends Loggable {
127 def testPing: Unit = {
128 assumeTrue(LogicTestsAssumptions.EnableSprayTests)
130 val service = Actor.actorOf(new SprayPingService("spray-root-service")).start()
131 val server = Actor.actorOf(new HttpServer()).start()
132 val client = Actor.actorOf(new HttpClient()).start()
134 val dialog = HttpDialog("localhost", 8080)
135 val result = dialog.send(HttpRequest(method = GET, uri = "/ping", headers = HttpHeader("Content-Type", "text/plain; charset=UTF-8")::Nil)).end
136 result onComplete { future =>
138 case Some(Right(response)) =>
139 logger.info("Response class : %s".format(response.getClass))
140 logger.info("Response status : %s".format(response.status))
141 logger.info("Response headers: %s".format(response.headers.map(hh => (hh.name, hh.value)).mkString(", ")))
142 logger.info("Response body : %s".format(response.bodyAsString))
144 logger.error("Error: %s".format(other))