Lift Comet Chat Example

I recently did a presentation on Lift. A lot of the materials were drawn from:David Pollak’s Java One Presentation and Marius Danciu’s Presentation. I posted the slides at linkedin. I wanted to demostrated Lift’s strength. So I created a quick Comet Chat example based on David’s code.

There were quite a few requests on the code. Instead of just create a zip file to let you download it. I’m going to walk you through how to build it.

First you need maven2. You can’t do anything with lift without it. You can download it here Come back to this when you finish downloading and installing it. You need to be able to issue mvn command.

Next we are going to create the lift project. For this one, we’ll use the lift-archetype-blank archetype.

mvn archetype:generate -U \
  -DarchetypeGroupId=net.liftweb \
  -DarchetypeArtifactId=lift-archetype-blank \
  -DarchetypeVersion=1.0 \
  -DremoteRepositories=http://scala-tools.org/repo-releases \
  -DgroupId=demo.app \
  -DartifactId=chat \
  -Dversion=1.0-SNAPSHOT

After tons of maven stuff scrolling through your screen. When it’s done. A directory called chat will be created. Now let’s run it to make sure it works.

cd chat
mvn jetty:run

If this part worked. You’ll see jetty up and running at port 8080. You can check it out by going to http://localhost:8080 on your browser.

Hit Ctrl-C and stop the running jetty. Onward to the next part.

Now you need to create src/main/scala/demo/app/comet/Chat.scala

package demo.app.comet

import scala.actors.Actor
import Actor._
import net.liftweb._
import http._
import js._
import SHtml._
import JsCmds._

case class Messages(msgs: List[String])

object ChatServer extends Actor with ListenerManager {
  private var msgs: List[String] = Nil

  protected def createUpdate = Messages(msgs)

  override def highPriority = {
    case s: String if s.length > 0 =>
      msgs ::= s
      updateListeners()
  }

  this.start
}

class Chat extends CometActor with CometListenee
{
  private var msgs: List[String] = Nil

  def render =
    { msgs.reverse.map( m =>
  • {m}
  • ) }
{ ajaxText("", s => {ChatServer ! s; Noop}) }
protected def registerWith = ChatServer override def highPriority = { case Messages(m) => msgs = m ; reRender(false) } }

That takes care of the code. You now have to include it in the view. To do this, edit src/main/webapp/index.html

The default file looks like below

<lift :surround with="default" at="content">
                <h2>Welcome to your project!</h2>
                <p><lift:helloWorld.howdy /></p>
</lift:surround>

Replace it with

<lift :surround with="default" at="content">
                <lift:comet type="Chat" />
</lift:surround>

That’s it. Now issue

mvn jetty:run

And you’ll see the Comet Chat in all its glory.

Comments (6)

Bjarte Stien KarlsenAugust 18th, 2009 at 6:31 am

At first I did not get your example to work. The problem I found was that the view code did not invoke comet correctly and did not close the tags correctly. This works:

Bjarte Stien KarlsenAugust 18th, 2009 at 6:32 am

That comment did not include the code. Here is a gist of it

http://gist.github.com/169681

MAugust 18th, 2009 at 10:05 am

Thanks for the catch, the syntax highlighting js messed it up. I put in

<lift:surround with="default" at="content">
  <lift:comet type="Chat" />
</lift:surround>

the js stripped and realigned stuff on the fly. I removed the call to the js. It looks right now. It’s ironic often posting code to the web is one of the hardest. :)

Sorry about that. I should’ve noticed. Because it messed up the default index.html generated by lift too.

fengboAugust 20th, 2009 at 9:00 pm

compile error:
type mismatch;
[WARNING] found : List[String]
[WARNING] required: net.liftweb.http.RenderOut
[WARNING] msgs.reverse.map( m => {m})
[WARNING]

fengboAugust 20th, 2009 at 9:04 pm

sorry for the previous message. The syntax highlighter hide some code and I mis copied.

MAugust 20th, 2009 at 9:08 pm

no problem, glad you find this useful.