Scala lift : Access Session Information In Actors.


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.


// This class set the locale in Session using S Object

object SetLocale{

   S.set("locale","it")

}

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.


// Following code call the actor . Here I bang a message to Actor
// MyActor should print the message along with user locale.

object CallTheActor{
   (new MyActor).start ! "Hello"
}

class MyActor{
 def act() {
    react {
         case msg => println(msg +"In "+S.get("locale").openOr("")
          }
    }
}

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).

object CallTheActor{
   (new MyActor).start ! ("Hello",S.session.open_!)
}

class MyActor{
 def act() {
    react {
         case (msg,session:LiftSession) => {S.initIfUninitted(session){
             S.initIfUninitted(session){
              println(msg +"In "+S.get("locale").openOr("")
               }
             }
          }
    }
}

/* There are two changes in the code. 
1. Pass the LiftSession (S.session.open_!) along with actual message while bang the message to MyActor.
2. use S.initIfUninitted(session) { } block to access Session Information.

Now Every thing will work fine. By using S.initIfUninitted you can initialize the session object explicitly in the Actor.

About mayankbairagi

Software Developer
This entry was posted in Web. Bookmark the permalink.

2 Responses to Scala lift : Access Session Information In Actors.

  1. Tylor says:

    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!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s