Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
package jp.t2v.lab.play2.stackc

import play.api.mvc._
import scala.collection.concurrent.TrieMap
import scala.concurrent.ExecutionContext
import scala.util.{Try, Failure, Success}
import java.util.concurrent.ConcurrentHashMap
import scala.collection.JavaConverters._
import scala.util.{Failure, Success}

trait StackableController {
self: Controller =>

implicit def executionContext: ExecutionContext = ExecutionContext.Implicits.global

final def StackAction[A](p: BodyParser[A], params: (RequestAttributeKey, Any)*)(f: RequestWithAttributes[A] => Result): Action[A] = Action(p) { req =>
val request = RequestWithAttributes(req, new ConcurrentHashMap(params.toMap.asJava))
final def StackAction[A](p: BodyParser[A], params: (RequestAttributeKey[_], Any)*)(f: RequestWithAttributes[A] => Result): Action[A] = Action(p) { req =>
val request = new RequestWithAttributes(req, new TrieMap[RequestAttributeKey[_], Any] ++= params)
try {
cleanup(request, proceed(request)(f))
} catch {
case e: Exception => cleanupOnFailed(request, e); throw e
}
}

def StackAction(params: (RequestAttributeKey, Any)*)(f: RequestWithAttributes[AnyContent] => Result): Action[AnyContent] = StackAction(parse.anyContent, params: _*)(f)
def StackAction(params: (RequestAttributeKey[_], Any)*)(f: RequestWithAttributes[AnyContent] => Result): Action[AnyContent] = StackAction(parse.anyContent, params: _*)(f)

def StackAction(f: RequestWithAttributes[AnyContent] => Result): Action[AnyContent] = StackAction()(f)

Expand All @@ -42,18 +41,19 @@ trait StackableController {

}

trait RequestAttributeKey
trait RequestAttributeKey[A]

case class RequestWithAttributes[A](underlying: Request[A], attributes: java.util.Map[RequestAttributeKey, Any]) extends WrappedRequest[A](underlying) {
class RequestWithAttributes[A](underlying: Request[A], attributes: TrieMap[RequestAttributeKey[_], Any]) extends WrappedRequest[A](underlying) {

def getAs[B](key: RequestAttributeKey): Option[B] = {
Option(attributes.get(key)).flatMap { item =>
Try(item.asInstanceOf[B]).toOption
def get[B](key: RequestAttributeKey[B]): Option[B] =
attributes.get(key).flatMap { item =>
try Some(item.asInstanceOf[B]) catch {
case _: ClassCastException => None
}
}
}

/** side effect! */
def set(key: RequestAttributeKey, value: Any): RequestWithAttributes[A] = {
def set[B](key: RequestAttributeKey[B], value: B): RequestWithAttributes[A] = {
attributes.put(key, value)
this
}
Expand Down
8 changes: 4 additions & 4 deletions sample/app/controllers/stack/AuthElement.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import jp.t2v.lab.play20.auth.{Auth, AuthConfig}
trait AuthElement extends StackableController {
self: Controller with Auth with AuthConfig =>

case object AuthKey extends RequestAttributeKey
case object AuthorityKey extends RequestAttributeKey
case object AuthKey extends RequestAttributeKey[User]
case object AuthorityKey extends RequestAttributeKey[Authority]

override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Result): Result = {
(for {
authority <- req.getAs[Authority](AuthorityKey).toRight(authorizationFailed(req)).right
authority <- req.get(AuthorityKey).toRight(authorizationFailed(req)).right
user <- authorized(authority)(req).right
} yield super.proceed(req.set(AuthKey, user))(f)).merge
}

implicit def loggedIn[A](implicit req: RequestWithAttributes[A]): User = req.getAs[User](AuthKey).get
implicit def loggedIn[A](implicit req: RequestWithAttributes[A]): User = req.get(AuthKey).get

}
8 changes: 4 additions & 4 deletions sample/app/controllers/stack/DBSessionElement.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import jp.t2v.lab.play2.stackc.{RequestWithAttributes, RequestAttributeKey, Stac
trait DBSessionElement extends StackableController {
self: Controller =>

case object DBSessionKey extends RequestAttributeKey
case object DBSessionKey extends RequestAttributeKey[(DB, DBSession)]

override def proceed[A](req: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Result): Result = {
val db = DB.connect()
Expand All @@ -18,7 +18,7 @@ trait DBSessionElement extends StackableController {

override def cleanupOnSucceeded[A](req: RequestWithAttributes[A]): Unit = {
try {
req.getAs[(DB, DBSession)](DBSessionKey).map { case (db, session) =>
req.get(DBSessionKey).map { case (db, session) =>
db.currentTx.commit()
session.close()
}
Expand All @@ -29,7 +29,7 @@ trait DBSessionElement extends StackableController {

override def cleanupOnFailed[A](req: RequestWithAttributes[A], e: Exception): Unit = {
try {
req.getAs[(DB, DBSession)](DBSessionKey).map { case (db, session) =>
req.get(DBSessionKey).map { case (db, session) =>
db.currentTx.rollback()
session.close()
}
Expand All @@ -38,6 +38,6 @@ trait DBSessionElement extends StackableController {
}
}

implicit def dbSession[A](implicit req: RequestWithAttributes): DBSession = req.getAs[(DB, DBSession)](DBSessionKey).get._2 // throw
implicit def dbSession[A](implicit req: RequestWithAttributes[A]): DBSession = req.get(DBSessionKey).get._2 // throw

}