summaryrefslogtreecommitdiff
path: root/cask/src/cask/main/Decorators.scala
diff options
context:
space:
mode:
Diffstat (limited to 'cask/src/cask/main/Decorators.scala')
-rw-r--r--cask/src/cask/main/Decorators.scala44
1 files changed, 43 insertions, 1 deletions
diff --git a/cask/src/cask/main/Decorators.scala b/cask/src/cask/main/Decorators.scala
index 573c139..0a68cba 100644
--- a/cask/src/cask/main/Decorators.scala
+++ b/cask/src/cask/main/Decorators.scala
@@ -1,7 +1,7 @@
package cask.main
import cask.internal.{Conversion, Router}
-import cask.internal.Router.ArgReader
+import cask.internal.Router.{ArgReader, EntryPoint}
import cask.model.{Request, Response}
/**
@@ -23,6 +23,48 @@ trait Decorator[InnerReturned, Input]{
def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned
def getParamParser[T](implicit p: InputParser[T]) = p
}
+object Decorator{
+ /**
+ * A stack of [[Decorator]]s is invoked recursively: each decorator's `wrapFunction`
+ * is invoked around the invocation of all inner decorators, with the inner-most
+ * decorator finally invoking the route's [[EntryPoint.invoke]] function.
+ *
+ * Each decorator (and the final `Endpoint`) contributes a dictionary of name-value
+ * bindings, which are eventually all passed to [[EntryPoint.invoke]]. Each decorator's
+ * dictionary corresponds to a different argument list on [[EntryPoint.invoke]]. The
+ * bindings passed from the router are aggregated with those from the `EndPoint` and
+ * used as the first argument list.
+ */
+ def invoke(ctx: Request,
+ metadata: Routes.EndpointMetadata[_],
+ routes: Routes,
+ routeBindings: Map[String, String],
+ remainingDecorators: List[RawDecorator],
+ bindings: List[Map[String, Any]]): Router.Result[Any] = try {
+ remainingDecorators match {
+ case head :: rest =>
+ head.wrapFunction(
+ ctx,
+ args => invoke(ctx, metadata, routes, routeBindings, rest, args :: bindings)
+ .asInstanceOf[Router.Result[cask.model.Response.Raw]]
+ )
+
+ case Nil =>
+ metadata.endpoint.wrapFunction(ctx, { (endpointBindings: Map[String, Any]) =>
+ val mergedEndpointBindings = endpointBindings ++ routeBindings.mapValues(metadata.endpoint.wrapPathSegment)
+ val finalBindings = mergedEndpointBindings :: bindings
+
+ metadata.entryPoint
+ .asInstanceOf[EntryPoint[cask.main.Routes, cask.model.Request]]
+ .invoke(routes, ctx, finalBindings)
+ .asInstanceOf[Router.Result[Nothing]]
+ })
+ }
+ // Make sure we wrap any exceptions that bubble up from decorator
+ // bodies, so outer decorators do not need to worry about their
+ // delegate throwing on them
+ }catch{case e: Throwable => Router.Result.Error.Exception(e) }
+}
/**
* A [[RawDecorator]] is a decorator that operates on the raw request and