SlideShare a Scribd company logo
Overview of Lift Web Framework




Vikas Hazrati
www.xebiaindia.com
Today There is a Wide Choice of
       Web Frameworks
As Developers It is Hard to Make a
            Choice
Every Framework Has its Own Set
           of Pitfalls
But Quick Development is Still an
            Option
Overview Of Lift Framework
Why is Lift Better?
      Convention over
       configuration                            Clean separation of presentation
                                                       content and logic




       Leverage the                                                 Responsive
Scala programming language                                          community




     Concise code increases                            Powerful AJAX & Comet
          productivity                                        Support


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




           cd helloworld
           mvn jetty:run
Overview Of Lift Framework
index.html

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




class HelloWorld {
  def howdy = <span>Welcome to helloworld at {new
_root_.java.util.Date}</span>
}
default.html
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:lift="http://liftweb.net/">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-
8" />
<meta name="description" content="" />
<meta name="keywords" content="" />

<title>demo.helloworld:helloworld:1.0-SNAPSHOT</title>
<script id="jquery" src="/classpath/jquery.js"
type="text/javascript"></script>
</head>
<body>
<lift:bind name="content" />
<lift:Menu.builder />
<lift:msgs/>
</body>
</html>
Boot Class
package bootstrap.liftweb

import    _root_.net.liftweb.util._
import    _root_.net.liftweb.http._
import    _root_.net.liftweb.sitemap._
import    _root_.net.liftweb.sitemap.Loc._
import    Helpers._

/**
  * A class that's instantiated early and run.      It allows the
application
  * to modify lift's environment
  */
class Boot {
  def boot {
    // where to search snippet
    LiftRules.addToPackages("demo.helloworld")

        // Build SiteMap
        val entries = Menu(Loc("Home", List("index"), "Home")) ::
Nil
        LiftRules.setSiteMap(SiteMap(entries:_*))
    }
}
Lift Entry Point
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<filter>
  <filter-name>LiftFilter</filter-name>
  <display-name>Lift Filter</display-name>
  <description>The Filter that intercepts lift
calls</description>
  <filter-class>net.liftweb.http.LiftFilter</filter-class>
</filter>


<filter-mapping>
  <filter-name>LiftFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

</web-app>
Lift’s Main Objects


  net.liftweb.http.S
                             net.liftweb.http.SHtml


net.liftweb.http.LiftRules
Template           Snippets




           Boot               Adding AJAX
           class                 Spice




           Model
Model
Maps to rdbms




class ToDo extends LongKeyedMapper[ToDo] with IdPK {
  def getSingleton = ToDo
  object done extends MappedBoolean(this)
  object owner extends MappedLongForeignKey(this, User)
  object priority extends MappedInt(this) {
    override def defaultValue = 5
  }
  object desc extends MappedPoliteString(this, 128)
}
object ToDo extends ToDo with LongKeyedMetaMapper[ToDo]

                                     Provides meta functionality
                                           Like finders etc
Persistence
Mapper and Record Frameworks
                            Per instance
     Mapper

                                 Global
   MetaMapper
                                                           Record
                                Per field
   MappedField


<project ...>
...
<dependencies>
  ...
  <dependency>
    <groupId>net.liftweb</groupId>
    <artifactId>lift-mapper</artifactId>
    <version>1.0</version> <!-- or 1.1-SNAPSHOT, etc -->
  </dependency>
</dependencies>
...
</project>
Database Connection
class Boot {
 def boot {
   ...
   DB.defineConnectionManager(DefaultConnectionIdentifier, DBVendor)
  Schemifier.schemify(true, Log.infoF _, User, ToDo)



           import _root_.net.liftweb.mapper._
           import _root_.java.sql._
           object DBVendor extends ConnectionManager {
            // Force load the driver
            Class.forName("org.postgresql.Driver")
            // define methods
            def newConnection(name : ConnectionIdentifier) = {
              try {
                Full(DriverManager.getConnection(
                   "jdbc:postgresql://localhost/mydatabase",
                   "root", "secret"))
              } catch {
                case e : Exception => e.printStackTrace; Empty
              }
            }
            def releaseConnection (conn : Connection) { conn.close }
import _root_.java.math.MathContext
class Expense extends LongKeyedMapper[Expense] with IdPK {
  def getSingleton = Expense
  object dateOf extends MappedDateTime(this)
  object description extends MappedString(this,100)
  object amount extends MappedDecimal(this, MathContext.DECIMAL64, 2)
  object account extends MappedLongForeignKey(this, Account)
}



create            save           delete       count     countByInsecureSQL


findAll         findAllByInsecureSQL      findAllByPreparedStatement


         findAllFields
Templates
Templates

                Lift tag


<lift:surround with="default" at="content">
<head><title>Hello!</title></head>
<lift:Hello.world />
</lift:surround>
                                  Snippet
Views
    class ExpenseView extends LiftView {
     override def dispatch = {
       case "enumerate" => doEnumerate _
     }
     def doEnumerate () : NodeSeq = {
       ...

        <lift:surround with="default" at="content">
        { expenseItems.toTable }
        </lift:surround>
    }
}
Tags
<lift:snippet type="MyClass:render" />        snippet
<lift:MyClass.render />
<lift:MyClass />
                                                            surround
<lift:surround with="template_name" at=”binding”>
        children
</lift:surround>

 <lift:bind name=”binding_name” />           bind


  <div class="accountUpdates">
  < lift : comet type="AccountMonitor">             comet
    <ul><account:entries>
      <li><entry:time/> : <entry:user /> :
 <entry:amount /></li>
    </account:entries></ul>
  </ lift : comet>
  </div>
Snippets




View              Logic
<lift:Util.out>                    Lift tags
         Please Log In <b>Dude</b>
         </lift:Util.out>


                                             Corresponding
                                                Snippet
package com.liftworkshop.snippet                 code
import scala.xml.{NodeSeq}
import com.liftworkshop._
import model._
class Util {
  def in(html: NodeSeq) =
   if (User.loggedIn_?) html else NodeSeq.Empty
  def out(html: NodeSeq) =
   if (!User.loggedIn_?) html else NodeSeq.Empty
}
Overview Of Lift Framework
Snippets
 class Ledger {
   def balance (content : NodeSeq) : NodeSeq =
 Text(currentLedger.formattedBalance)
 }
                              class Ledger {
                                def balance (content : NodeSeq) : NodeSeq =
                                 <p>{currentLedger.formattedBalance}
                                 as of <lift:Util.time /></p>
                              }


<lift:Ledger.balance>
<ledger:balance/> as of <ledger:time />
</lift:Ledger.balance>
                                      class Ledger {
                                        def balance (content : NodeSeq ) : NodeSeq =
                                         bind ("ledger", content,
                                            "balance" -> Text(currentLedger.formattedBalance),
                                            "time" -> Text((new java.util.Date).toString))
                                      }
Snippets are Stateless
               Cookies




             SessionVar




             RequestVar



            StatefulSnippet
               Subclass
Form Processing




Post/Get
                             JSON

                AJAX
Form Processing
<html>
...
<lift:Show.myForm form="POST">
 <tr>
  <td>Name</td>
  <td><f:name><input type="text"/></f:name></td>
 </tr>
 <tr>
  <td>Birthyear</td>
  <td><f:year>
       <select><option>2007</option></select>
  </f:year></td>
 </tr>
 <tr>
  <td>&nbsp;</td>
  <td><input type="submit" value="Add"/></td>
 </tr>
</lift:Show.myForm>
</html>
Form Processing

class Show {
  def myForm(xhtml: NodeSeq) = {
    var name = ""
    def handleYear(year: String) {
      ... the form’s been submitted... do something
    }
    bind("f", xhtml, "name" -> text(name, name = _),
               "year" -> select((1900 to 2007).
                    toList.map(_.toString).
                    reverse.map(v => (v, v)),
                    Empty, handleYear _))
  }
}
Goodies
ProtoUser and MegaProtoUser




                                  class User extends ProtoUser[User] {
                                  override def shortName = firstName.is
                                  override lastNameDisplayName = "surname"
                              }
AJAX and Comet
JavaScript
import JsCmds._
import JE._
var myName = ""
bind(...
  "name" -> text(myName, myName = _, "id" -> "myName"),
  "submit" -> submit("Save", ..., "onclick" ->
   JsIf(JsEq(ValById("myName"), ""),
     Alert("You must provide a name") & JsReturn(false))
   )
)


import net.liftweb.http.js.yui.YUIArtifacts
class Boot {
  def boot = {
   ...
   LiftRules.jsArtifacts = YUIArtifacts
   ...
}
AJAX and Comet
AJAX and Comet
Comet Based on Scala Actors
AJAX
 <lift:TD.list all_id="all_todos">
 <div id="all_todos">
   <div>Exclude done <todo:exclude/></div>
   <ul>
    <todo:list>
         <li>
        <todo:check><input type="checkbox"/></todo:check>
        <todo:priority>
          <select><option>1</option></select>
        </todo:priority>
        <todo:desc>To Do</todo:desc>
      </li>
    </todo:list>
   </ul>
 </div>
</lift:TD.list>
def list(html: NodeSeq) = {
  val id = S.attr("all_id").open_!
  def inner(): NodeSeq = {
    def reDraw() = SetHtml(id, inner())
    bind("todo", html,
        "exclude" ->
          ajaxCheckbox(QueryNotDone, v =>
{QueryNotDone(v); reDraw}),
        "list" -> doList(reDraw) _)
  }
  inner()              private def doList(reDraw: () => JsCmd)(html: NodeSeq):
}                      NodeSeq =
                        toShow.
                        flatMap(td =>
                         bind("todo", html,
                             "check" -> ajaxCheckbox(td.done,
                                      v => {td.done(v).save; reDraw()}),
                             "priority" ->
                             ajaxSelect(ToDo.priorityList,
                       Full(td.priority.toString),
                                      v => {td.priority(v.toInt).save;
                       reDraw()}),
                             "desc" -> desc(td, reDraw)
                         ))


  private def desc(td: ToDo, reDraw: () => JsCmd) =
 swappable(<span>{td.desc}</span>,
         <span>{ajaxText(td.desc,
                     v => {td.desc(v).save; reDraw()})}
         </span>)
Comet
<lift:surround with="default" at="content">
  <lift:comet type="Clock" name="Other">
          Current Time: <clk:time>Missing Clock</clk:time>
     </lift:comet>
</lift:surround>
                                    class Clock extends CometActor {
                                     override def defaultPrefix = Full("clk")
                                     def render = bind("time" -> timeSpan)
                                     def timeSpan = (<span id="time">{timeNow}</span>)
                                     // schedule a ping every 10 seconds so we redraw
                                     ActorPing.schedule(this, Tick, 10000L)
                                     override def lowPriority : PartialFunction[Any, Unit] = {
                                       case Tick => {
                                         println("Got tick " + new Date());
                                         partialUpdate(SetHtml("time", Text(timeNow.toString)))
                                         // schedule an update in 10 seconds
                                         ActorPing.schedule(this, Tick, 10000L)
                                       }
                                     }
                                   }
                                   case object Tick
Lift Architecture
Rails v/s Lift

For single request processing, the lift code, running inside Tomcat, ran 4
times faster than the Rails code running inside Mongrel. However, the CPU
utilization was less than 5% in the lift version, where it was 100% of 1 CPU
(on a dual core machine) for the Rails version. For multiple simultaneous
requests being made from multiple machines, we're seeing better than 20x
performance of the lift code versus the Rails code with 5 Mongrel instances.
Once again, the lift code is not using very much CPU and the Rails code is
pegging both CPUs.


                        http://lambda-the-ultimate.org/node/2147
Lots of Choices
Overview Of Lift Framework

More Related Content

PDF
EWD 3 Training Course Part 20: The DocumentNode Object
PDF
Single page webapps & javascript-testing
PDF
EWD 3 Training Course Part 14: Using Ajax for QEWD Messages
PDF
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
PDF
What's new in DWR version 3
PDF
Http4s, Doobie and Circe: The Functional Web Stack
PPTX
Open Source Ajax Solution @OSDC.tw 2009
PDF
RicoLiveGrid
EWD 3 Training Course Part 20: The DocumentNode Object
Single page webapps & javascript-testing
EWD 3 Training Course Part 14: Using Ajax for QEWD Messages
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
What's new in DWR version 3
Http4s, Doobie and Circe: The Functional Web Stack
Open Source Ajax Solution @OSDC.tw 2009
RicoLiveGrid

What's hot (19)

PDF
Alfredo-PUMEX
PDF
EWD 3 Training Course Part 22: Traversing Documents using DocumentNode Objects
PDF
td_mxc_rubyrails_shin
PDF
Brew up a Rich Web Application with Cappuccino
PDF
From framework coupled code to #microservices through #DDD /by @codelytv
PDF
EWD 3 Training Course Part 9: Complex QEWD Messages and Responses
ODP
High Performance XQuery Processing in PHP with Zorba by Vikram Vaswani
PDF
Simplify AJAX using jQuery
PDF
Test-driven Development with AEM
PDF
Node.js in action
PDF
Unit Testing at Scale
PDF
Build Widgets
PPT
jQuery Objects
PPTX
JavaFX and Scala in the Cloud
PPTX
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
PDF
YouDrup_in_Drupal
PPT
JavaScript JQUERY AJAX
PDF
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
PDF
HTML5 JavaScript APIs
Alfredo-PUMEX
EWD 3 Training Course Part 22: Traversing Documents using DocumentNode Objects
td_mxc_rubyrails_shin
Brew up a Rich Web Application with Cappuccino
From framework coupled code to #microservices through #DDD /by @codelytv
EWD 3 Training Course Part 9: Complex QEWD Messages and Responses
High Performance XQuery Processing in PHP with Zorba by Vikram Vaswani
Simplify AJAX using jQuery
Test-driven Development with AEM
Node.js in action
Unit Testing at Scale
Build Widgets
jQuery Objects
JavaFX and Scala in the Cloud
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
YouDrup_in_Drupal
JavaScript JQUERY AJAX
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HTML5 JavaScript APIs
Ad

Viewers also liked (6)

PDF
Banking application & software solutions at competitive rate
PPTX
Our Experience in Banking and Financial Services
PDF
Thought Paper: Overview of Banking Applications
PPT
bankauditinITEnv
PPTX
IS Audit and Internal Controls
DOC
Bank audit slideshare
Banking application & software solutions at competitive rate
Our Experience in Banking and Financial Services
Thought Paper: Overview of Banking Applications
bankauditinITEnv
IS Audit and Internal Controls
Bank audit slideshare
Ad

Similar to Overview Of Lift Framework (20)

PDF
Lift 2 0
 
KEY
Html5 For Jjugccc2009fall
PPT
J query b_dotnet_ug_meet_12_may_2012
PPT
Play!ng with scala
PPTX
Html5 and web technology update
PPTX
Writing HTML5 Web Apps using Backbone.js and GAE
PDF
Rich Portlet Development in uPortal
PPTX
PPTX
Google app engine by example
PDF
Rails is not just Ruby
PDF
Web Components With Rails
PDF
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
PPTX
Android development with Scala and SBT
KEY
Scala & Lift (JEEConf 2012)
PDF
London Scala UG - Lift:Getting started with Scala
PDF
Rails vs Web2py
PDF
A full introductory guide to React
PDF
JSF 2.0 Preview
PDF
Lift 2 0
 
Html5 For Jjugccc2009fall
J query b_dotnet_ug_meet_12_may_2012
Play!ng with scala
Html5 and web technology update
Writing HTML5 Web Apps using Backbone.js and GAE
Rich Portlet Development in uPortal
Google app engine by example
Rails is not just Ruby
Web Components With Rails
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
Android development with Scala and SBT
Scala & Lift (JEEConf 2012)
London Scala UG - Lift:Getting started with Scala
Rails vs Web2py
A full introductory guide to React
JSF 2.0 Preview

More from Xebia IT Architects (20)

PPTX
Using Graph Databases For Insights Into Connected Data.
PPT
Use Cases of #Grails in #WebApplications
PPT
When elephants dance , enterprise goes mobile !
PDF
DevOps demystified
PDF
Exploiting vulnerabilities in location based commerce
PDF
Modelling RESTful applications – Why should I not use verbs in REST url
PDF
Scrumban - benefits of both the worlds
PDF
#Continuous delivery with #Deployit
PDF
Continuous integration using thucydides(bdd) with selenium
PPTX
Battlefield agility
PPTX
Fish!ing for agile teams
PDF
Xebia-Agile consulting and training offerings
PPT
Xebia e-Commerce / mCommerce Solutions
PPT
Growth at Xebia
PPTX
A warm and prosperous Happy Diwali to all our clients
PDF
"We Plan to double our headcount" - MD, Xebia India
PPT
Agile 2.0 - Our Road to Mastery
PPTX
Agile FAQs by Shrikant Vashishtha
PPTX
Agile Team Dynamics by Bhavin Chandulal Javia
PPTX
Practicing Agile in Offshore Environment by Himanshu Seth & Imran Mir
Using Graph Databases For Insights Into Connected Data.
Use Cases of #Grails in #WebApplications
When elephants dance , enterprise goes mobile !
DevOps demystified
Exploiting vulnerabilities in location based commerce
Modelling RESTful applications – Why should I not use verbs in REST url
Scrumban - benefits of both the worlds
#Continuous delivery with #Deployit
Continuous integration using thucydides(bdd) with selenium
Battlefield agility
Fish!ing for agile teams
Xebia-Agile consulting and training offerings
Xebia e-Commerce / mCommerce Solutions
Growth at Xebia
A warm and prosperous Happy Diwali to all our clients
"We Plan to double our headcount" - MD, Xebia India
Agile 2.0 - Our Road to Mastery
Agile FAQs by Shrikant Vashishtha
Agile Team Dynamics by Bhavin Chandulal Javia
Practicing Agile in Offshore Environment by Himanshu Seth & Imran Mir

Recently uploaded (20)

PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Cloud computing and distributed systems.
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Big Data Technologies - Introduction.pptx
PPT
Teaching material agriculture food technology
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
Digital-Transformation-Roadmap-for-Companies.pptx
Understanding_Digital_Forensics_Presentation.pptx
Mobile App Security Testing_ A Comprehensive Guide.pdf
Cloud computing and distributed systems.
The Rise and Fall of 3GPP – Time for a Sabbatical?
Big Data Technologies - Introduction.pptx
Teaching material agriculture food technology
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Reach Out and Touch Someone: Haptics and Empathic Computing
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Per capita expenditure prediction using model stacking based on satellite ima...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Chapter 3 Spatial Domain Image Processing.pdf
Review of recent advances in non-invasive hemoglobin estimation
How UI/UX Design Impacts User Retention in Mobile Apps.pdf

Overview Of Lift Framework

  • 1. Overview of Lift Web Framework Vikas Hazrati www.xebiaindia.com
  • 2. Today There is a Wide Choice of Web Frameworks
  • 3. As Developers It is Hard to Make a Choice
  • 4. Every Framework Has its Own Set of Pitfalls
  • 5. But Quick Development is Still an Option
  • 7. Why is Lift Better? Convention over configuration Clean separation of presentation content and logic Leverage the Responsive Scala programming language community Concise code increases Powerful AJAX & Comet productivity Support Highly Scalable
  • 8. mvn archetype:generate -U -DarchetypeGroupId=net.liftweb -DarchetypeArtifactId=lift-archetype-blank -DarchetypeVersion=1.0 -DremoteRepositories=http://scala-tools.org/repo- releases -DgroupId=demo.helloworld -DartifactId=helloworld -Dversion=1.0-SNAPSHOT cd helloworld mvn jetty:run
  • 10. index.html <lift:surround with="default" at="content"> <h2>Welcome to your project!</h2> <p><lift:helloWorld.howdy /></p> </lift:surround> class HelloWorld { def howdy = <span>Welcome to helloworld at {new _root_.java.util.Date}</span> }
  • 11. default.html <html xmlns="http://www.w3.org/1999/xhtml" xmlns:lift="http://liftweb.net/"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF- 8" /> <meta name="description" content="" /> <meta name="keywords" content="" /> <title>demo.helloworld:helloworld:1.0-SNAPSHOT</title> <script id="jquery" src="/classpath/jquery.js" type="text/javascript"></script> </head> <body> <lift:bind name="content" /> <lift:Menu.builder /> <lift:msgs/> </body> </html>
  • 12. Boot Class package bootstrap.liftweb import _root_.net.liftweb.util._ import _root_.net.liftweb.http._ import _root_.net.liftweb.sitemap._ import _root_.net.liftweb.sitemap.Loc._ import Helpers._ /** * A class that's instantiated early and run. It allows the application * to modify lift's environment */ class Boot { def boot { // where to search snippet LiftRules.addToPackages("demo.helloworld") // Build SiteMap val entries = Menu(Loc("Home", List("index"), "Home")) :: Nil LiftRules.setSiteMap(SiteMap(entries:_*)) } }
  • 13. Lift Entry Point <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <filter> <filter-name>LiftFilter</filter-name> <display-name>Lift Filter</display-name> <description>The Filter that intercepts lift calls</description> <filter-class>net.liftweb.http.LiftFilter</filter-class> </filter> <filter-mapping> <filter-name>LiftFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
  • 14. Lift’s Main Objects net.liftweb.http.S net.liftweb.http.SHtml net.liftweb.http.LiftRules
  • 15. Template Snippets Boot Adding AJAX class Spice Model
  • 16. Model
  • 17. Maps to rdbms class ToDo extends LongKeyedMapper[ToDo] with IdPK { def getSingleton = ToDo object done extends MappedBoolean(this) object owner extends MappedLongForeignKey(this, User) object priority extends MappedInt(this) { override def defaultValue = 5 } object desc extends MappedPoliteString(this, 128) } object ToDo extends ToDo with LongKeyedMetaMapper[ToDo] Provides meta functionality Like finders etc
  • 19. Mapper and Record Frameworks Per instance Mapper Global MetaMapper Record Per field MappedField <project ...> ... <dependencies> ... <dependency> <groupId>net.liftweb</groupId> <artifactId>lift-mapper</artifactId> <version>1.0</version> <!-- or 1.1-SNAPSHOT, etc --> </dependency> </dependencies> ... </project>
  • 20. Database Connection class Boot { def boot { ... DB.defineConnectionManager(DefaultConnectionIdentifier, DBVendor) Schemifier.schemify(true, Log.infoF _, User, ToDo) import _root_.net.liftweb.mapper._ import _root_.java.sql._ object DBVendor extends ConnectionManager { // Force load the driver Class.forName("org.postgresql.Driver") // define methods def newConnection(name : ConnectionIdentifier) = { try { Full(DriverManager.getConnection( "jdbc:postgresql://localhost/mydatabase", "root", "secret")) } catch { case e : Exception => e.printStackTrace; Empty } } def releaseConnection (conn : Connection) { conn.close }
  • 21. import _root_.java.math.MathContext class Expense extends LongKeyedMapper[Expense] with IdPK { def getSingleton = Expense object dateOf extends MappedDateTime(this) object description extends MappedString(this,100) object amount extends MappedDecimal(this, MathContext.DECIMAL64, 2) object account extends MappedLongForeignKey(this, Account) } create save delete count countByInsecureSQL findAll findAllByInsecureSQL findAllByPreparedStatement findAllFields
  • 23. Templates Lift tag <lift:surround with="default" at="content"> <head><title>Hello!</title></head> <lift:Hello.world /> </lift:surround> Snippet
  • 24. Views class ExpenseView extends LiftView { override def dispatch = { case "enumerate" => doEnumerate _ } def doEnumerate () : NodeSeq = { ... <lift:surround with="default" at="content"> { expenseItems.toTable } </lift:surround> } }
  • 25. Tags <lift:snippet type="MyClass:render" /> snippet <lift:MyClass.render /> <lift:MyClass /> surround <lift:surround with="template_name" at=”binding”> children </lift:surround> <lift:bind name=”binding_name” /> bind <div class="accountUpdates"> < lift : comet type="AccountMonitor"> comet <ul><account:entries> <li><entry:time/> : <entry:user /> : <entry:amount /></li> </account:entries></ul> </ lift : comet> </div>
  • 26. Snippets View Logic
  • 27. <lift:Util.out> Lift tags Please Log In <b>Dude</b> </lift:Util.out> Corresponding Snippet package com.liftworkshop.snippet code import scala.xml.{NodeSeq} import com.liftworkshop._ import model._ class Util { def in(html: NodeSeq) = if (User.loggedIn_?) html else NodeSeq.Empty def out(html: NodeSeq) = if (!User.loggedIn_?) html else NodeSeq.Empty }
  • 29. Snippets class Ledger { def balance (content : NodeSeq) : NodeSeq = Text(currentLedger.formattedBalance) } class Ledger { def balance (content : NodeSeq) : NodeSeq = <p>{currentLedger.formattedBalance} as of <lift:Util.time /></p> } <lift:Ledger.balance> <ledger:balance/> as of <ledger:time /> </lift:Ledger.balance> class Ledger { def balance (content : NodeSeq ) : NodeSeq = bind ("ledger", content, "balance" -> Text(currentLedger.formattedBalance), "time" -> Text((new java.util.Date).toString)) }
  • 30. Snippets are Stateless Cookies SessionVar RequestVar StatefulSnippet Subclass
  • 32. Form Processing <html> ... <lift:Show.myForm form="POST"> <tr> <td>Name</td> <td><f:name><input type="text"/></f:name></td> </tr> <tr> <td>Birthyear</td> <td><f:year> <select><option>2007</option></select> </f:year></td> </tr> <tr> <td>&nbsp;</td> <td><input type="submit" value="Add"/></td> </tr> </lift:Show.myForm> </html>
  • 33. Form Processing class Show { def myForm(xhtml: NodeSeq) = { var name = "" def handleYear(year: String) { ... the form’s been submitted... do something } bind("f", xhtml, "name" -> text(name, name = _), "year" -> select((1900 to 2007). toList.map(_.toString). reverse.map(v => (v, v)), Empty, handleYear _)) } }
  • 34. Goodies ProtoUser and MegaProtoUser class User extends ProtoUser[User] { override def shortName = firstName.is override lastNameDisplayName = "surname" }
  • 36. JavaScript import JsCmds._ import JE._ var myName = "" bind(... "name" -> text(myName, myName = _, "id" -> "myName"), "submit" -> submit("Save", ..., "onclick" -> JsIf(JsEq(ValById("myName"), ""), Alert("You must provide a name") & JsReturn(false)) ) ) import net.liftweb.http.js.yui.YUIArtifacts class Boot { def boot = { ... LiftRules.jsArtifacts = YUIArtifacts ... }
  • 39. Comet Based on Scala Actors
  • 40. AJAX <lift:TD.list all_id="all_todos"> <div id="all_todos"> <div>Exclude done <todo:exclude/></div> <ul> <todo:list> <li> <todo:check><input type="checkbox"/></todo:check> <todo:priority> <select><option>1</option></select> </todo:priority> <todo:desc>To Do</todo:desc> </li> </todo:list> </ul> </div> </lift:TD.list>
  • 41. def list(html: NodeSeq) = { val id = S.attr("all_id").open_! def inner(): NodeSeq = { def reDraw() = SetHtml(id, inner()) bind("todo", html, "exclude" -> ajaxCheckbox(QueryNotDone, v => {QueryNotDone(v); reDraw}), "list" -> doList(reDraw) _) } inner() private def doList(reDraw: () => JsCmd)(html: NodeSeq): } NodeSeq = toShow. flatMap(td => bind("todo", html, "check" -> ajaxCheckbox(td.done, v => {td.done(v).save; reDraw()}), "priority" -> ajaxSelect(ToDo.priorityList, Full(td.priority.toString), v => {td.priority(v.toInt).save; reDraw()}), "desc" -> desc(td, reDraw) )) private def desc(td: ToDo, reDraw: () => JsCmd) = swappable(<span>{td.desc}</span>, <span>{ajaxText(td.desc, v => {td.desc(v).save; reDraw()})} </span>)
  • 42. Comet <lift:surround with="default" at="content"> <lift:comet type="Clock" name="Other"> Current Time: <clk:time>Missing Clock</clk:time> </lift:comet> </lift:surround> class Clock extends CometActor { override def defaultPrefix = Full("clk") def render = bind("time" -> timeSpan) def timeSpan = (<span id="time">{timeNow}</span>) // schedule a ping every 10 seconds so we redraw ActorPing.schedule(this, Tick, 10000L) override def lowPriority : PartialFunction[Any, Unit] = { case Tick => { println("Got tick " + new Date()); partialUpdate(SetHtml("time", Text(timeNow.toString))) // schedule an update in 10 seconds ActorPing.schedule(this, Tick, 10000L) } } } case object Tick
  • 44. Rails v/s Lift For single request processing, the lift code, running inside Tomcat, ran 4 times faster than the Rails code running inside Mongrel. However, the CPU utilization was less than 5% in the lift version, where it was 100% of 1 CPU (on a dual core machine) for the Rails version. For multiple simultaneous requests being made from multiple machines, we're seeing better than 20x performance of the lift code versus the Rails code with 5 Mongrel instances. Once again, the lift code is not using very much CPU and the Rails code is pegging both CPUs. http://lambda-the-ultimate.org/node/2147