Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Remove global Spray.system ActorSystem

  • Loading branch information...
commit dbfe0d5ec03e609e6d7b2222ca0cc3fd6e5dca95 1 parent 1c4f5dd
@sirthias sirthias authored
Showing with 153 additions and 103 deletions.
  1. +1 −2  spray-base/src/main/scala/cc/spray/http/HttpHeader.scala
  2. +4 −4 spray-base/src/main/scala/cc/spray/typeconversion/DefaultMarshallers.scala
  3. +6 −1 spray-server/src/main/scala/cc/spray/Directives.scala
  4. +5 −3 spray-server/src/main/scala/cc/spray/ErrorHandling.scala
  5. +0 −1  spray-server/src/main/scala/cc/spray/SprayCanRootService.scala
  6. +3 −0  spray-server/src/main/scala/cc/spray/authentication/AuthenticationCaching.scala
  7. +16 −13 spray-server/src/main/scala/cc/spray/authentication/FromConfigUserPassAuthenticator.scala
  8. +6 −6 spray-server/src/main/scala/cc/spray/authentication/LdapAuthenticator.scala
  9. +4 −5 spray-server/src/main/scala/cc/spray/caching/Cache.scala
  10. +4 −5 spray-server/src/main/scala/cc/spray/caching/LruCache.scala
  11. +9 −5 spray-server/src/main/scala/cc/spray/connectors/ConnectorServlet.scala
  12. +23 −3 spray-server/src/main/scala/cc/spray/connectors/Initializer.scala
  13. +3 −1 spray-server/src/main/scala/cc/spray/connectors/Jetty7ConnectorServlet.scala
  14. +3 −1 spray-server/src/main/scala/cc/spray/connectors/Servlet30ConnectorServlet.scala
  15. +4 −2 spray-server/src/main/scala/cc/spray/connectors/Tomcat6ConnectorServlet.scala
  16. +3 −0  spray-server/src/main/scala/cc/spray/directives/CacheDirectives.scala
  17. +4 −2 spray-server/src/main/scala/cc/spray/directives/ChunkingDirectives.scala
  18. +4 −3 spray-server/src/main/scala/cc/spray/directives/DebuggingDirectives.scala
  19. +5 −4 spray-server/src/main/scala/cc/spray/directives/ExecutionDirectives.scala
  20. +6 −2 spray-server/src/main/scala/cc/spray/directives/FileAndResourceDirectives.scala
  21. +5 −1 spray-server/src/main/scala/cc/spray/directives/SecurityDirectives.scala
  22. +5 −5 spray-server/src/main/scala/cc/spray/test/RouteResultComponent.scala
  23. +7 −0 spray-server/src/main/scala/cc/spray/test/SprayTest.scala
  24. +2 −2 spray-server/src/test/scala/cc/spray/HttpServiceLogicSpec.scala
  25. +9 −2 spray-server/src/test/scala/cc/spray/authentication/CachingAuthenticatorSpec.scala
  26. +4 −1 spray-server/src/test/scala/cc/spray/authentication/FromConfigUserPassAuthenticatorSpec.scala
  27. +5 −2 spray-server/src/test/scala/cc/spray/caching/ExpiringLruCacheSpec.scala
  28. +1 −2  spray-server/src/test/scala/cc/spray/directives/MarshallingDirectivesSpec.scala
  29. +0 −2  spray-server/src/test/scala/cc/spray/directives/SecurityDirectivesSpec.scala
  30. +2 −0  spray-server/src/test/scala/cc/spray/test/AbstractSprayTest.scala
  31. +0 −23 spray-util/src/main/scala/cc/spray/util/Spray.scala
View
3  spray-base/src/main/scala/cc/spray/http/HttpHeader.scala
@@ -20,7 +20,6 @@ package http
import parser.HttpParser
import java.lang.String
-import util.Spray
abstract class HttpHeader extends Product {
val name = productPrefix.replace("$minus", "-")
@@ -36,7 +35,7 @@ object HttpHeader {
case Left(error) =>
val msg = "Illegal HTTP header '" + name + "':\n" + error
if (SprayBaseSettings.RelaxedHeaderParsing) {
- Spray.system.log.warning(msg)
+ //log.warning(msg)
HttpHeaders.CustomHeader(name, value)
} else throw new HttpException(StatusCodes.BadRequest, msg)
case Right(header) => header
View
8 spray-base/src/main/scala/cc/spray/typeconversion/DefaultMarshallers.scala
@@ -23,8 +23,7 @@ import HttpCharsets._
import xml.NodeSeq
import java.nio.CharBuffer
import akka.dispatch.Future
-import akka.actor.{Props, PoisonPill, Actor}
-import util.Spray
+import akka.actor.{ActorRefFactory, Props, PoisonPill, Actor}
trait DefaultMarshallers extends MultipartMarshallers {
@@ -73,12 +72,13 @@ trait DefaultMarshallers extends MultipartMarshallers {
def apply(sel: ContentTypeSelector) = MarshalWith(_.handleError)
}
- implicit def streamMarshaller[T](implicit marshaller: Marshaller[T]) = new Marshaller[Stream[T]] {
+ implicit def streamMarshaller[T](implicit marshaller: Marshaller[T],
+ refFactory: ActorRefFactory): Marshaller[Stream[T]] = new Marshaller[Stream[T]] {
def apply(selector: ContentTypeSelector) = {
marshaller(selector) match {
case x: CantMarshal => x
case MarshalWith(converter) => MarshalWith { ctx => stream =>
- Spray.system.actorOf(Props(new ChunkingActor(ctx, stream, converter))) ! stream
+ refFactory.actorOf(Props(new ChunkingActor(ctx, stream, converter))) ! stream
}
}
}
View
7 spray-server/src/main/scala/cc/spray/Directives.scala
@@ -18,6 +18,7 @@ package cc.spray
import directives._
import typeconversion._
+import akka.actor.ActorSystem
/**
* Directives is the central trait you should mix in to get access to ''sprays'' Route building directives.
@@ -40,4 +41,8 @@ trait Directives
with FromStringDeserializers
with ReceptaclePimps
-object Directives extends Directives
+object Directives {
+ def apply(_system: ActorSystem): Directives = new Directives {
+ def system = _system
+ }
+}
View
8 spray-server/src/main/scala/cc/spray/ErrorHandling.scala
@@ -18,19 +18,21 @@ package cc.spray
import http._
import StatusCodes._
-import util.{Spray, IllegalResponseException}
+import util.IllegalResponseException
+import akka.event.LoggingAdapter
trait ErrorHandling {
+ def log: LoggingAdapter
protected[spray] def responseForException(request: Any, e: Exception): HttpResponse = {
e match {
case HttpException(failure, reason) =>
- Spray.system.log.warning("Request {} could not be handled normally, completing with {} response ({})",
+ log.warning("Request {} could not be handled normally, completing with {} response ({})",
request, failure.value, reason)
HttpResponse(failure, reason)
case e: IllegalResponseException => throw e
case e: Exception =>
- Spray.system.log.error(e, "Error during processing of request {}", request)
+ log.error(e, "Error during processing of request {}", request)
HttpResponse(InternalServerError, "Internal Server Error:\n" + e.toString)
}
}
View
1  spray-server/src/main/scala/cc/spray/SprayCanRootService.scala
@@ -24,7 +24,6 @@ import typeconversion.ChunkSender
import SprayCanConversions._
import akka.dispatch.{Promise, Future}
import akka.util.Duration
-import util.Spray
/**
* A specialized [[cc.spray.RootService]] for connector-less deployment on top of the ''spray-can'' `HttpServer`.
View
3  spray-server/src/main/scala/cc/spray/authentication/AuthenticationCaching.scala
@@ -18,6 +18,7 @@ package cc.spray
package authentication
import caching.{LruCache, Cache}
+import akka.actor.ActorSystem
/**
@@ -32,6 +33,8 @@ trait AuthenticationCaching[U] extends UserPassAuthenticator[U] {
*/
protected val authCache: Cache[Option[U]] = LruCache()
+ implicit def system: ActorSystem
+
abstract override def apply(userPass: Option[(String, String)]) = {
authCache.fromFuture(userPass) {
super.apply(userPass)
View
29 spray-server/src/main/scala/cc/spray/authentication/FromConfigUserPassAuthenticator.scala
@@ -17,9 +17,8 @@
package cc.spray
package authentication
-import akka.dispatch.Promise
import com.typesafe.config.ConfigException
-import util.Spray
+import akka.dispatch.{ExecutionContext, Promise}
/**
@@ -36,17 +35,21 @@ import util.Spray
* }
* }}}
*/
-object FromConfigUserPassAuthenticator extends UserPassAuthenticator[BasicUserContext] {
- def apply(userPass: Option[(String, String)]) = Promise.successful(
- userPass.flatMap {
- case (user, pass) => {
- try {
- val pw = SprayServerSettings.Users.getString(user)
- if (pw == pass) Some(BasicUserContext(user)) else None
- } catch {
- case _: ConfigException => None
+object FromConfigUserPassAuthenticator {
+ def apply()(implicit executor: ExecutionContext): UserPassAuthenticator[BasicUserContext] = {
+ new UserPassAuthenticator[BasicUserContext] {
+ def apply(userPass: Option[(String, String)]) = Promise.successful(
+ userPass.flatMap {
+ case (user, pass) => {
+ try {
+ val pw = SprayServerSettings.Users.getString(user)
+ if (pw == pass) Some(BasicUserContext(user)) else None
+ } catch {
+ case _: ConfigException => None
+ }
+ }
}
- }
+ )
}
- )(Spray.system.dispatcher)
+ }
}
View
12 spray-server/src/main/scala/cc/spray/authentication/LdapAuthenticator.scala
@@ -23,7 +23,7 @@ import javax.naming.ldap.InitialLdapContext
import javax.naming.directory.{SearchControls, SearchResult, Attribute}
import collection.JavaConverters._
import akka.dispatch.{Promise, Future}
-import util.Spray
+import akka.actor.ActorSystem
/**
* The LdapAuthenticator faciliates user/password authentication against an LDAP server.
@@ -35,8 +35,8 @@ import util.Spray
* matching a given user name. If exactly one user entry is found another LDAP bind operation is performed using the
* principal DN of the found user entry to validate the password.
*/
-class LdapAuthenticator[T](config: LdapAuthConfig[T]) extends UserPassAuthenticator[T] {
- def log = Spray.system.log
+class LdapAuthenticator[T](config: LdapAuthConfig[T])(implicit system: ActorSystem) extends UserPassAuthenticator[T] {
+ def log = system.log
def apply(userPass: Option[(String, String)]) = {
def auth3(entry: LdapQueryResult, pass: String) = {
@@ -78,10 +78,10 @@ class LdapAuthenticator[T](config: LdapAuthConfig[T]) extends UserPassAuthentica
}
userPass match {
- case Some((user, pass)) => Future(auth1(user, pass))(Spray.system.dispatcher)
+ case Some((user, pass)) => Future(auth1(user, pass))
case None =>
log.warning("LdapAuthenticator.apply called with empty userPass, authentication not possible")
- Promise.successful(None)(Spray.system.dispatcher)
+ Promise.successful(None)
}
}
@@ -134,5 +134,5 @@ class LdapAuthenticator[T](config: LdapAuthConfig[T]) extends UserPassAuthentica
}
object LdapAuthenticator {
- def apply[T](config: LdapAuthConfig[T]) = new LdapAuthenticator(config)
+ def apply[T](config: LdapAuthConfig[T])(implicit system: ActorSystem) = new LdapAuthenticator(config)
}
View
9 spray-server/src/main/scala/cc/spray/caching/Cache.scala
@@ -18,7 +18,6 @@ package cc.spray
package caching
import akka.dispatch._
-import util.Spray
import akka.util.NonFatal
/**
@@ -36,7 +35,7 @@ trait Cache[V] {
/**
* Wraps the given expression with caching support.
*/
- def apply(expr: => V): Future[V] = apply { promise =>
+ def apply(expr: => V)(implicit executor: ExecutionContext): Future[V] = apply { promise =>
try {
promise.success(expr)
} catch {
@@ -47,8 +46,8 @@ trait Cache[V] {
/**
* Wraps the given function with caching support.
*/
- def apply(func: Promise[V] => Unit): Future[V] = fromFuture(key) {
- val p = Promise[V]()(Spray.system.dispatcher)
+ def apply(func: Promise[V] => Unit)(implicit executor: ExecutionContext): Future[V] = fromFuture(key) {
+ val p = Promise[V]()
func(p)
p
}
@@ -63,7 +62,7 @@ trait Cache[V] {
/**
* Supplies a cache entry for the given key from the given expression.
*/
- def fromFuture(key: Any)(future: => Future[V]): Future[V]
+ def fromFuture(key: Any)(future: => Future[V])(implicit executor: ExecutionContext): Future[V]
/**
* Removes the cache item for the given key. Returns the removed item if it was found (and removed).
View
9 spray-server/src/main/scala/cc/spray/caching/LruCache.scala
@@ -21,7 +21,6 @@ import akka.util.Duration
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap
import annotation.tailrec
import akka.dispatch.{Promise, ExecutionContext, Future}
-import util.Spray
object LruCache {
/**
@@ -57,8 +56,8 @@ final class SimpleLruCache[V](val maxCapacity: Int, val initialCapacity: Int) ex
def get(key: Any) = Option(store.get(key))
- def fromFuture(key: Any)(future: => Future[V]): Future[V] = {
- val promise = Promise[V]()(Spray.system.dispatcher)
+ def fromFuture(key: Any)(future: => Future[V])(implicit executor: ExecutionContext): Future[V] = {
+ val promise = Promise[V]()
store.putIfAbsent(key, promise) match {
case null => future.onComplete { value =>
promise.complete(value)
@@ -113,9 +112,9 @@ final class ExpiringLruCache[V](maxCapacity: Int, initialCapacity: Int,
else get(key) // nope, try again
}
- def fromFuture(key: Any)(future: => Future[V]): Future[V] = {
+ def fromFuture(key: Any)(future: => Future[V])(implicit executor: ExecutionContext): Future[V] = {
def insert() = {
- val newEntry = new Entry(Promise[V]()(Spray.system.dispatcher))
+ val newEntry = new Entry(Promise[V]())
val valueFuture = store.put(key, newEntry) match {
case null => future
case entry => if (isAlive(entry)) {
View
14 spray-server/src/main/scala/cc/spray/connectors/ConnectorServlet.scala
@@ -25,16 +25,20 @@ import StatusCodes._
import MediaTypes._
import java.util.concurrent.{TimeUnit, CountDownLatch}
import java.io.{IOException, InputStream}
-import util.Spray
+import akka.actor.ActorSystem
-private[connectors] abstract class ConnectorServlet(containerName: String) extends HttpServlet {
+private[connectors] abstract class ConnectorServlet extends HttpServlet {
import SprayServletSettings._
- lazy val rootService = Spray.system.actorFor(RootActorPath)
- lazy val timeoutActor = if (TimeoutActorPath.isEmpty) rootService else Spray.system.actorFor(TimeoutActorPath)
- def log = Spray.system.log
+ var system: ActorSystem = _
+ lazy val rootService = system.actorFor(RootActorPath)
+ lazy val timeoutActor = if (TimeoutActorPath.isEmpty) rootService else system.actorFor(TimeoutActorPath)
+ def log = system.log
var timeout: Int = RequestTimeout.toInt
+ def containerName: String
+
override def init() {
+ system = getServletContext.getAttribute(Initializer.SystemAttrName).asInstanceOf[ActorSystem]
log.info("Initializing {} <=> Spray Connector", containerName)
log.info("Async timeout for all requests is {} ms", timeout)
}
View
26 spray-server/src/main/scala/cc/spray/connectors/Initializer.scala
@@ -17,35 +17,55 @@
package cc.spray.connectors
import javax.servlet.{ServletContextListener, ServletContextEvent}
-import cc.spray.util.Spray
import akka.util.Switch
import cc.spray.SprayServletSettings
import akka.config.ConfigurationException
+import akka.actor.ActorSystem
class Initializer extends ServletContextListener {
private val booted = new Switch(false)
+ private lazy val system = ActorSystem("servlet")
def contextInitialized(e: ServletContextEvent) {
booted switchOn {
println("Starting spray application ...")
val loader = getClass.getClassLoader
Thread.currentThread.setContextClassLoader(loader)
+
+ e.getServletContext.setAttribute(Initializer.SystemAttrName, system)
+
SprayServletSettings.BootClasses match {
case Nil =>
throw new ConfigurationException("No boot classes configured. " +
"Please specify at least one boot class in the spray.servlet.boot-classes config setting.")
case classes =>
for (className <- classes) {
- loader.loadClass(className).newInstance()
+ systemConstructor(loader, className).newInstance(system)
}
}
}
}
+ private def systemConstructor(loader: ClassLoader, className: String) = {
+ try {
+ loader.loadClass(className).getConstructor(classOf[ActorSystem])
+ } catch {
+ case e: ClassNotFoundException =>
+ throw new ConfigurationException("Configured boot class " + className + " cannot be found", e)
+ case e: NoSuchMethodException =>
+ throw new ConfigurationException("Configured boot class " + className +
+ " does not define required constructor with one parameter of type `akka.actor.ActorSystem`", e)
+ }
+ }
+
def contextDestroyed(e: ServletContextEvent) {
booted switchOff {
println("Shutting down spray application ...")
- Spray.system.shutdown()
+ system.shutdown()
}
}
+}
+
+object Initializer {
+ private[connectors] val SystemAttrName = "spray.servlet.system"
}
View
4 spray-server/src/main/scala/cc/spray/connectors/Jetty7ConnectorServlet.scala
@@ -24,7 +24,9 @@ import java.util.concurrent.atomic.AtomicBoolean
/**
* The spray connector servlet for Jetty 7.
*/
-class Jetty7ConnectorServlet extends ConnectorServlet("Jetty 7") {
+class Jetty7ConnectorServlet extends ConnectorServlet {
+
+ def containerName = "Jetty 7"
override def service(req: HttpServletRequest, resp: HttpServletResponse) {
requestContext(req, resp, responder(req, resp)).foreach(rootService ! _)
View
4 spray-server/src/main/scala/cc/spray/connectors/Servlet30ConnectorServlet.scala
@@ -24,7 +24,9 @@ import java.util.concurrent.atomic.AtomicBoolean
/**
* The spray connector servlet for all servlet 3.0 containers.
*/
-class Servlet30ConnectorServlet extends ConnectorServlet("Servlet API 3.0") {
+class Servlet30ConnectorServlet extends ConnectorServlet {
+
+ def containerName = "Servlet API 3.0"
override def service(req: HttpServletRequest, resp: HttpServletResponse) {
requestContext(req, resp, responder(req, resp)).foreach(rootService ! _)
View
6 spray-server/src/main/scala/cc/spray/connectors/Tomcat6ConnectorServlet.scala
@@ -23,11 +23,13 @@ import org.apache.catalina.{CometEvent, CometProcessor}
/**
* The spray connector servlet for Tomcat 6.
*/
-class Tomcat6ConnectorServlet extends ConnectorServlet("Tomcat 6") with CometProcessor {
+class Tomcat6ConnectorServlet extends ConnectorServlet with CometProcessor {
+
+ def containerName = "Tomcat 6"
override def service(req: HttpServletRequest, resp: HttpServletResponse) {
throw new RuntimeException("The Tomcat6ConnectorServlet does not support the standard blocking Servlet API, " +
- "you need to enable support for asynchronous HTTP in your Tomcat6 server instance!")
+ "you need to enable support for asynchronous HTTP in your Tomcat6 server instance!")
}
def event(ev: CometEvent) {
View
3  spray-server/src/main/scala/cc/spray/directives/CacheDirectives.scala
@@ -21,10 +21,13 @@ import caching._
import http._
import HttpHeaders._
import CacheDirectives._
+import akka.actor.ActorSystem
private[spray] trait CacheDirectives {
this: BasicDirectives =>
+ implicit def system: ActorSystem
+
/**
* Wraps its inner Route with caching support using the given [[cc.spray.caching.Cache]] implementation and
* keyer function.
View
6 spray-server/src/main/scala/cc/spray/directives/ChunkingDirectives.scala
@@ -18,12 +18,14 @@ package cc.spray
package directives
import util.make
-import http.{ContentType, HttpContent}
-import typeconversion.{DefaultMarshallers, SimpleMarshaller}
+import typeconversion.DefaultMarshallers
+import akka.actor.ActorSystem
private[spray] trait ChunkingDirectives {
this: BasicDirectives =>
+ implicit def system: ActorSystem
+
/**
* Automatically converts a non-rejected response from its inner route into a chunked response of which each chunk
* (save the very last) has the given size.
View
7 spray-server/src/main/scala/cc/spray/directives/DebuggingDirectives.scala
@@ -18,11 +18,13 @@ package cc.spray
package directives
import http.{HttpResponse, HttpRequest, HttpMessage}
-import util.Spray
+import akka.actor.ActorSystem
trait DebuggingDirectives {
this: BasicDirectives with MiscDirectives =>
+ def system: ActorSystem
+
def logRequest(marker: String = "") = transformRequest(logMessage("Request", marker))
def logResponse(marker: String = "") = transformResponse(logMessage("Response", marker))
@@ -62,6 +64,5 @@ trait DebuggingDirectives {
msg
}
- private def log = Spray.system.log
-
+ private def log = system.log
}
View
9 spray-server/src/main/scala/cc/spray/directives/ExecutionDirectives.scala
@@ -17,20 +17,21 @@
package cc.spray
package directives
-import util.Spray
-import akka.actor.{Props, Actor}
import akka.util.NonFatal
+import akka.actor.{ActorLogging, ActorSystem, Props, Actor}
private[spray] trait ExecutionDirectives {
this: BasicDirectives =>
+ def system: ActorSystem
+
/**
* Returns a Route that executes its inner Route in the content of a newly spawned actor.
*/
def detach = transformRoute { route => ctx =>
- Spray.system.actorOf {
+ system.actorOf {
Props {
- new Actor() with ErrorHandling {
+ new Actor() with ErrorHandling with ActorLogging {
def receive = {
case ctx: RequestContext => try {
route(ctx)
View
8 spray-server/src/main/scala/cc/spray/directives/FileAndResourceDirectives.scala
@@ -24,11 +24,14 @@ import HttpHeaders._
import util.identityFunc
import java.io.{FileInputStream, File}
import java.util.Arrays
-import typeconversion.{DefaultMarshallers, SimpleMarshaller}
+import typeconversion.{Marshaller, DefaultMarshallers, SimpleMarshaller}
+import akka.actor.ActorSystem
private[spray] trait FileAndResourceDirectives {
this: SimpleDirectives with ExecutionDirectives with MiscDirectives with DefaultMarshallers =>
+ def system: ActorSystem
+
/**
* Returns a Route that completes GET requests with the content of the given file. The actual I/O operation is
* running detached in the context of a newly spawned actor, so it doesn't block the current thread (but potentially
@@ -61,6 +64,7 @@ private[spray] trait FileAndResourceDirectives {
if (file.length() >= SprayServerSettings.FileChunkingThresholdSize) {
import FileChunking._
implicit val marshaller = fileChunkMarshaller(contentType)
+ implicit def sys = system
ctx.complete(fileChunkStream(file))
} else ctx.complete(responseFromFile(file, contentType).get)
} else ctx.reject() // reject without specific rejection => same as unmatched "path" directive
@@ -195,7 +199,7 @@ object FileChunking {
chunkStream()
}
- def fileChunkMarshaller(contentType: ContentType) = new SimpleMarshaller[FileChunk] {
+ def fileChunkMarshaller(contentType: ContentType): Marshaller[FileChunk] = new SimpleMarshaller[FileChunk] {
val canMarshalTo = contentType :: Nil
def marshal(value: FileChunk, contentType: ContentType) = HttpContent(contentType, value.buffer)
}
View
6 spray-server/src/main/scala/cc/spray/directives/SecurityDirectives.scala
@@ -20,10 +20,13 @@ package directives
import authentication.{BasicHttpAuthenticator, FromConfigUserPassAuthenticator}
import http.StatusCodes._
import akka.dispatch.Future
+import akka.actor.{ActorLogging, ActorSystem}
private[spray] trait SecurityDirectives {
this: BasicDirectives =>
+ implicit def system: ActorSystem
+
/**
* Wraps its inner Route with authentication support.
* Uses the given authenticator to authenticate the user and extract an object representing the users identity.
@@ -51,6 +54,7 @@ private[spray] trait SecurityDirectives {
def authenticate[U](authentication: Future[Authentication[U]]): (U => Route) => Route = { innerRoute => ctx =>
authentication onComplete {
new (Either[Throwable, Either[Rejection, U]] => Unit) with ErrorHandling {
+ def log = system.log
def apply(value: Either[Throwable, Either[Rejection, U]]) {
value match {
case Right(Right(userContext)) =>
@@ -85,6 +89,6 @@ private[spray] trait SecurityDirectives {
* Convenience method for the creation of a BasicHttpAuthenticator instance.
*/
def httpBasic[U](realm: String = "Secured Resource",
- authenticator: UserPassAuthenticator[U] = FromConfigUserPassAuthenticator): BasicHttpAuthenticator[U] =
+ authenticator: UserPassAuthenticator[U] = FromConfigUserPassAuthenticator()) =
new BasicHttpAuthenticator[U](realm, authenticator)
}
View
10 spray-server/src/main/scala/cc/spray/test/RouteResultComponent.scala
@@ -22,8 +22,7 @@ import http.{HttpResponse, HttpHeader, ChunkExtension, MessageChunk}
import akka.util.Duration
import java.util.concurrent.{TimeUnit, CountDownLatch}
import typeconversion.ChunkSender
-import akka.dispatch.Promise
-import util.Spray
+import akka.dispatch.{ExecutionContext, Promise}
trait RouteResultComponent {
@@ -41,7 +40,7 @@ trait RouteResultComponent {
private val latch = new CountDownLatch(1)
private var virginal = true
- def requestResponder = RequestResponder(
+ def requestResponder(implicit executor: ExecutionContext) = RequestResponder(
complete = resp => { saveResult(Right(resp)); latch.countDown() },
reject = rejs => { saveResult(Left(rejs)); latch.countDown() },
startChunkedResponse = resp => { saveResult(Right(resp)); new TestChunkSender() },
@@ -63,10 +62,11 @@ trait RouteResultComponent {
}
}
- class TestChunkSender(onSent: Option[Long => Unit] = None) extends ChunkSender {
+ class TestChunkSender(onSent: Option[Long => Unit] = None)
+ (implicit executor: ExecutionContext) extends ChunkSender {
def sendChunk(chunk: MessageChunk) = outer.synchronized {
chunks += chunk
- Promise.successful(())(Spray.system.dispatcher)
+ Promise.successful(())
}
def close(extensions: List[ChunkExtension], trailer: List[HttpHeader]) {
View
7 spray-server/src/main/scala/cc/spray/test/SprayTest.scala
@@ -23,6 +23,7 @@ import akka.util.Duration
import akka.util.duration._
import util._
import java.lang.Class
+import akka.actor.ActorSystem
/**
* Mix this trait into the class or trait containing your route and service tests.
@@ -31,6 +32,11 @@ import java.lang.Class
*/
trait SprayTest extends RouteResultComponent {
+ // we spin up a dedicated ActorSystem for the test
+ // CAUTION: you need to make sure to explicitly shut it down after all examples in this test have run,
+ // e.g., with specs2 you need to add a `step(system.shutdown())` to your test
+ implicit val system = ActorSystem()
+
def test(request: HttpRequest, timeout: Duration = 1000.millis)(route: Route): RoutingResultWrapper = {
val routeResult = new RouteResult
route {
@@ -48,6 +54,7 @@ trait SprayTest extends RouteResultComponent {
implicit def wrapRoute(theRoute: Route)
(implicit theRejectionHandler: RejectionHandler = RejectionHandler.Default) = {
new HttpServiceLogic {
+ def log = system.log
val route = theRoute
def rejectionHandler = theRejectionHandler
}
View
4 spray-server/src/test/scala/cc/spray/HttpServiceLogicSpec.scala
@@ -24,7 +24,7 @@ import HttpMethods._
import StatusCodes._
import MediaTypes._
import test.AbstractSprayTest
-import util.{Spray, IllegalResponseException}
+import util.IllegalResponseException
import xml.NodeSeq
import encoding._
import akka.dispatch.Promise
@@ -32,7 +32,7 @@ import akka.dispatch.Promise
class HttpServiceLogicSpec extends AbstractSprayTest {
implicit val userPassAuth = new UserPassAuthenticator[BasicUserContext] {
- def apply(userPass: Option[(String, String)]) = Promise.successful(None)(Spray.system.dispatcher)
+ def apply(userPass: Option[(String, String)]) = Promise.successful(None)
}
"The HttpServiceLogic" should {
View
11 spray-server/src/test/scala/cc/spray/authentication/CachingAuthenticatorSpec.scala
@@ -21,17 +21,22 @@ import org.specs2.mutable.Specification
import java.util.concurrent.atomic.AtomicInteger
import akka.dispatch.{Promise, Future}
import util._
+import akka.actor.ActorSystem
class CachingAuthenticatorSpec extends Specification {
+ implicit val system = ActorSystem()
+
class CountingAuthenticator extends UserPassAuthenticator[Int] {
val counter = new AtomicInteger
def apply(userPass: Option[(String, String)]): Future[Option[Int]] =
- Promise.successful(Some(counter.incrementAndGet()))(Spray.system.dispatcher)
+ Promise.successful(Some(counter.incrementAndGet()))
}
val CountingAuthenticator = new CountingAuthenticator
- val CachinggAuthenticator = new CountingAuthenticator with AuthenticationCaching[Int]
+ val CachinggAuthenticator = new CountingAuthenticator with AuthenticationCaching[Int] {
+ implicit def system = CachingAuthenticatorSpec.this.system
+ }
"the AuthenticationCaching" should {
"cache the auth results from the underlying UserPassAuthenticator" in {
@@ -45,4 +50,6 @@ class CachingAuthenticatorSpec extends Specification {
}
}
+ step(system.shutdown())
+
}
View
5 spray-server/src/test/scala/cc/spray/authentication/FromConfigUserPassAuthenticatorSpec.scala
@@ -18,14 +18,17 @@ package cc.spray
package authentication
import org.specs2.mutable.Specification
+import akka.actor.ActorSystem
import util._
class FromConfigUserPassAuthenticatorSpec extends Specification {
+ implicit val system = ActorSystem()
"the FromConfigUserPassAuthenticator" should {
"extract a BasicUserContext for users defined in the spray config" in {
- FromConfigUserPassAuthenticator(Some("Alice", "banana")).await mustEqual Some(BasicUserContext("Alice"))
+ FromConfigUserPassAuthenticator().apply(Some("Alice", "banana")).await mustEqual Some(BasicUserContext("Alice"))
}
}
+ step(system.shutdown())
}
View
7 spray-server/src/test/scala/cc/spray/caching/ExpiringLruCacheSpec.scala
@@ -22,10 +22,11 @@ import akka.util.Duration
import java.util.Random
import org.specs2.matcher.Matcher
import cc.spray.util._
-import akka.dispatch.{ExecutionContext, Future}
+import akka.dispatch.Future
+import akka.actor.ActorSystem
class ExpiringLruCacheSpec extends Specification {
- implicit def executor: ExecutionContext = Spray.system.dispatcher
+ implicit val system = ActorSystem()
"An LruCache" should {
"be initially empty" in {
@@ -120,6 +121,8 @@ class ExpiringLruCacheSpec extends Specification {
}
}
+ step(system.shutdown())
+
def lruCache[T](maxCapacity: Int = 500, initialCapacity: Int = 16,
timeToLive: Duration = Duration.Zero, timeToIdle: Duration = Duration.Zero) =
new ExpiringLruCache[T](maxCapacity, initialCapacity, timeToLive.toMillis, timeToIdle.toMillis)
View
3  spray-server/src/test/scala/cc/spray/directives/MarshallingDirectivesSpec.scala
@@ -27,7 +27,6 @@ import typeconversion._
import xml.{XML, NodeSeq}
import java.io.ByteArrayInputStream
import akka.dispatch.Future
-import util.Spray
class MarshallingDirectivesSpec extends AbstractSprayTest {
@@ -126,7 +125,7 @@ class MarshallingDirectivesSpec extends AbstractSprayTest {
"RequestContext.complete(Future)" should {
"correctly complete the request with the future result" in {
test(HttpRequest()) {
- completeWith(Future("yeah")(Spray.system.dispatcher))
+ completeWith(Future("yeah"))
}.response.content.as[String] mustEqual Right("yeah")
}
}
View
2  spray-server/src/test/scala/cc/spray/directives/SecurityDirectivesSpec.scala
@@ -21,11 +21,9 @@ import http._
import HttpHeaders._
import test.AbstractSprayTest
import authentication.BasicUserContext
-import util.Spray
import akka.dispatch.{ExecutionContext, Promise}
class SecurityDirectivesSpec extends AbstractSprayTest {
- implicit def executor: ExecutionContext = Spray.system.dispatcher
val dontAuth = new UserPassAuthenticator[BasicUserContext] {
def apply(userPass: Option[(String, String)]) = Promise.successful(None)
View
2  spray-server/src/test/scala/cc/spray/test/AbstractSprayTest.scala
@@ -3,6 +3,7 @@ package test
import http._
import org.specs2.mutable._
+import org.specs2.specification.{Fragments, Step}
abstract class AbstractSprayTest extends Specification with SprayTest with Directives {
@@ -10,4 +11,5 @@ abstract class AbstractSprayTest extends Specification with SprayTest with Direc
def echoComplete[T]: T => Route = { x => completeWith(x.toString) }
+ override def map(fs: => Fragments) = fs ^ Step(system.shutdown())
}
View
23 spray-util/src/main/scala/cc/spray/util/Spray.scala
@@ -1,23 +0,0 @@
-package cc.spray.util
-
-import akka.actor.ActorSystem
-import java.util.concurrent.atomic.AtomicReference
-import annotation.tailrec
-
-/**
- * For spray-1.0-M1 we use a global actor system for all spray-client and spray-server stuff,
- * since we'd like to port the spray 0.9 code to Akka 2.0 with as few changes as possible.
- * This global ActorSystem is going to go away with 1.0-M2 when we have an architecture that
- * was built from the ground up for Akka 2.0.
- */
-object Spray {
- private[this] val _system = new AtomicReference[ActorSystem]
-
- def set(system: ActorSystem): Boolean = _system.compareAndSet(null, system)
-
- @tailrec
- def system: ActorSystem = _system.get match {
- case null => set(ActorSystem("spray")); system
- case s => s
- }
-}
Please sign in to comment.
Something went wrong with that request. Please try again.