Problem: In Scala Lift Application. There are two ways to maintain and access the session information. Either we can use SessionVars or net.liftweb.http.S object. Each of them work significantly well until there are used in the scope of session.
Now the actual problem arise when I used Actor to get concurrency in scala lift application. Actor runs outside of the context of the session that you set the SessionVar or S object.I used scala Actor, Akka Actor, Lift Actor but no one is able to hold the session state.
In the context of session it is quite possible to get the locale using S.get(“locale”) throughout the application.
But I use Actor, It is not possible for Actor to maintain the session. so It is not possible to get locale from Session or S Object.
When you hit the Actor with the message “Hello”. MyActor shoud print ” Hello in it_IT “.
But unfortunately you are not so lucky. It prints “Hello in” instead of “Hello in it_IT”. This problem arise because Actor breaks the context of session so MyActor is not able to retrieve the Session information.
Solution : Fortunatly lift has initIfUninitted for rescue. It initialize the current request session if it’s not already initialized. Generally this is handled by Lift during request processing, but this method is available in case you want to use S outside the scope of a request (standard HTTP , Comet and Actor).
Now Every thing will work fine. By using S.initIfUninitted you can initialize the session object explicitly in the Actor.
Hi 🙂 I’m having some trouble getting your example to work. Can you please assist? My code below:
object SetLocale{
S.set(“locale”,”it”)
}
object CallTheActor {
def render = SHtml.onSubmit(x => {
MyActor ! (x, S.session) //This is the problem, method “def session” in S is of type Box[LiftSession] please see the API
SetValById(“clearcontents”, “”)
})
}
object MyActor extends LiftActor {
def messageHandler = {
case (msg, s:LiftSession) => S.initIfUninitted(s) { //Doesn’t match because “S.session” is Box[LiftSession]
println(msg +”In “+S.get(“locale”).openOr(“”))
}
/*
//If you add the case below you get a compiler error saying:
//found : net.liftweb.common.Box[net.liftweb.http.LiftSession]
//required: net.liftweb.http.LiftSession
//Check out S in the API you will see there is no method in S to simply call LiftSession, only method “def session” to call Box[LiftSession]
//Method initIfUninitted is S requires type LfitSession and not Box[LiftSession]
//So how do you give LiftSession to S.initIfUninitted(??) ?
case (msg, s:Box[LiftSession]) => S.initIfUninitted(s) {
println(msg +”In “+S.get(“locale”).openOr(“”))
}
}
*/
}
Hi Tylor,
This is a good catch. Thanks for finding the Typo.
>>MyActor ! (x, S.session) //This is the problem, method “def session” in S is of type Box[LiftSession] please see the API
But the actual call should be like this
MyActor ! (x, S.session.open_!) // Now this statement will hit the Actor with the LiftSession, instead of Box[LiftSession]
I hope, now this would work as expected.
Thank You!