4
votes

I'm trying to implement "request based" sessions in scalaquery in the play framework. I create a session using scalaquery and attempt to store it in the current http context, as follows:

def withTransaction[A](bp: BodyParser[A])(f: Request[A] => Result): Action[A] = {
   Action(bp) {
     request =>
       val context = Http.Context.current()
       val session = createSession()
       session.conn.setAutoCommit(false)
       context.args.put("scalaquery.session", session)
       try {
         val result = f(request)
         session.conn.commit()
         result
       }
       catch {
         case t: Throwable =>
           session.conn.rollback()
           throw t
       }
       finally {
         session.close()
         context.args.remove("scalaquery.session")
       }
   }
}

then i wrap my actions in my controllers like:

withTransaction(parse.anyContent) {
    Action {
       //code that produces a result here
    }
}

However, it crashes in the following line saying:

val context = Http.Context.current() 
[RuntimeException: There is no HTTP Context available from here.] 

So, why is the context not available? This code is called directly by the framework, so shouldn't the context be set by the time this code executes? Or am i using the wrong way for accessing the context?

EDIT: The "session" is of type org.scalaquery.session.Session. The reason why i want to set it in the HttpContext is so that the wrapped actions can access it in an "http scoped" fashion, i.e. That each request stores their session separately, yet all services that need a session can find it in a public scope that is separated per request.

1

1 Answers

1
votes

I think the problem is you're using the Java API with the Scala controller. Http.Context is only set if you're using the Java controller. Have you considered using the Scala Session API?

Also, another question is, why do you need to store the session in the context? I see you just remove it at the end anyway. If what you need is for the sub-actions to be able to access the session, you could just pass it in the function.

I'm just going to assume session is of type Session

def withTransaction[A](bp: BodyParser[A])(f: Session => Request[A] => Result): Action[A] = {
   Action(bp) {
     request =>
       val session = createSession()
       session.conn.setAutoCommit(false)
       try {
         val result = f(session)(request)
         session.conn.commit()
         result
       }
       catch {
         case t: Throwable =>
           session.conn.rollback()
           throw t
       }
       finally {
         session.close()
       }
   }
}

and your sub-actions would be

withTransaction(parse.anyContent) { session => request =>
    //code that produces a result here
}

you don't need to wrap this in Action anymore since it's already wrapped by withTransaction