/*
* Copyright 2007-2009 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
*/
package net.liftweb.http
import _root_.net.liftweb.util._
import Helpers._
import _root_.scala.collection.mutable.{HashMap, ListBuffer}
/**
* Keep session information around without the nastiness of naming session variables
* or the type-unsafety of casting the results.
* SessionVars are type-safe variables that map pretty directly to
* HttpSession attributes. Put stuff in and they are available for the
* life of the Session.
*
* SessionVar's can be used even from CometActor's as now S scope in a Cometctor is
* provided automatically.
*
* @param dflt - the default value of the session variable
*/
abstract class SessionVar[T](dflt: => T) extends AnyVar[T, SessionVar[T]](dflt) {
override protected def findFunc(name: String): Box[T] = S.session.flatMap(_.get(name))
override protected def setFunc(name: String, value: T): Unit = S.session.foreach(_.set(name, value))
override protected def clearFunc(name: String): Unit = S.session.foreach(_.unset(name))
override protected def wasInitialized(name: String): Boolean = {
val bn = name+"_inited_?"
val old: Boolean = S.session.flatMap(_.get(bn)) openOr false
S.session.foreach(_.set(bn, true))
old
}
protected override def registerCleanupFunc(in: LiftSession => Unit): Unit =
S.session.foreach(_.addSessionCleanup(in))
type CleanUpParam = LiftSession
}
/**
* Keep request-local information around without the nastiness of naming session variables
* or the type-unsafety of casting the results.
* RequestVars share their value through the scope of the current HTTP
* request. They have no value at the beginning of request servicing
* and their value is discarded at the end of request processing. They
* are helpful to share values across many snippets.
*
* @param dflt - the default value of the session variable
*/
abstract class RequestVar[T](dflt: => T) extends AnyVar[T, RequestVar[T]](dflt) {
type CleanUpParam = Box[LiftSession]
override protected def findFunc(name: String): Box[T] = RequestVarHandler.get(name)
override protected def setFunc(name: String, value: T): Unit = RequestVarHandler.set(name, this, value)
override protected def clearFunc(name: String): Unit = RequestVarHandler.clear(name)
override protected def wasInitialized(name: String): Boolean = {
val bn = name+"_inited_?"
val old: Boolean = RequestVarHandler.get(bn) openOr false
RequestVarHandler.set(bn, this, true)
old
}
override protected def registerCleanupFunc(in: Box[LiftSession] => Unit): Unit =
RequestVarHandler.addCleanupFunc(in)
}
trait CleanRequestVarOnSessionTransition {
self: RequestVar[_] =>
}
private[http] object RequestVarHandler {
private val vals: ThreadGlobal[HashMap[String, (RequestVar[_], Any)]] = new ThreadGlobal
private val cleanup: ThreadGlobal[ListBuffer[Box[LiftSession] => Unit]] = new ThreadGlobal
private val isIn: ThreadGlobal[String] = new ThreadGlobal
private val sessionThing: ThreadGlobal[Box[LiftSession]] = new ThreadGlobal
private[http] def get[T](name: String): Box[T] =
for (ht <- Box.legacyNullTest(vals.value);
v <- ht.get(name).map(_._2).asInstanceOf[Option[T]]) yield v;
private[http] def set[T](name: String, from: RequestVar[_], value: T): Unit =
for (ht <- Box.legacyNullTest(vals.value))
ht(name) = (from, value)
private[http] def clear(name: String): Unit =
for (ht <- Box.legacyNullTest(vals.value))
ht -= name
private[http] def addCleanupFunc(f: Box[LiftSession] => Unit): Unit =
for (cu <- Box.legacyNullTest(cleanup.value))
cu += f
def apply[T](session: Box[LiftSession], f: => T): T = {
if ("in" == isIn.value) {
val tv = vals.value
// remove all the session variables that are CleanRequestVarOnSessionTransition
val toRemove: Iterable[String] = tv.flatMap {
case (name, (it: CleanRequestVarOnSessionTransition, _)) => List(name)
case _ => Nil
}
toRemove.foreach(n => tv -= n)
sessionThing.set(session)
f
} else
isIn.doWith("in") (
vals.doWith(new HashMap) (
cleanup.doWith(new ListBuffer) {
sessionThing.doWith(session) {
val ret: T = f
cleanup.value.toList.foreach(clean => Helpers.tryo(clean(sessionThing.value)))
ret
}
}
))
}
}
object AnyVar {
implicit def whatSessionVarIs[T](in: SessionVar[T]): T = in.is
implicit def whatRequestVarIs[T](in: RequestVar[T]): T = in.is
}