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
Scala based 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
Scala based 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
}
Scala based 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
Scala based 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
Unit Testing at Scale
PDF
Node.js in action
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
Unit Testing at Scale
Node.js in action
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 (18)

DOC
Abhishek resume4
PPTX
Composición fotográfica miguel
PPTX
Management Information System- Information Technology Concepts
PDF
Affordable Credit to Vulnerable Female Micro Entrepreneurs
PPTX
Freedom of Expression and Trademark Rights in India
PDF
VALUATION OF OLD R.C.C. BUILDINGS
PDF
Using Pop Culture References in Advertisements? Just Do It Right | Orange Cou...
PPTX
PRINT JOURNALISM II- OBJECTIVES OF EDITING
PPTX
International Patent Classification IPC for Performing Patent Infringement Se...
PDF
How Businesses can Navigate Indian Markets | Patent Amendment Rules 2016 | Cu...
PPTX
The Whys, The Hows of Structural Audit of Buildings
PPTX
Pharmaceutical patents in india – compulsory licensing, health emergency & af...
PDF
Girish_BharadwajK_RESUME
PPTX
The Drugs and Magic Remedies (Objectionable Advertisements) Act, 1954
PPTX
feasibility study Chapter 4
PPTX
Press council of India
PPTX
IPR Protection for Hardware Startups - Patents, Trademarks, Copyrights and De...
PDF
WP Management Reporting Excellence_3
Abhishek resume4
Composición fotográfica miguel
Management Information System- Information Technology Concepts
Affordable Credit to Vulnerable Female Micro Entrepreneurs
Freedom of Expression and Trademark Rights in India
VALUATION OF OLD R.C.C. BUILDINGS
Using Pop Culture References in Advertisements? Just Do It Right | Orange Cou...
PRINT JOURNALISM II- OBJECTIVES OF EDITING
International Patent Classification IPC for Performing Patent Infringement Se...
How Businesses can Navigate Indian Markets | Patent Amendment Rules 2016 | Cu...
The Whys, The Hows of Structural Audit of Buildings
Pharmaceutical patents in india – compulsory licensing, health emergency & af...
Girish_BharadwajK_RESUME
The Drugs and Magic Remedies (Objectionable Advertisements) Act, 1954
feasibility study Chapter 4
Press council of India
IPR Protection for Hardware Startups - Patents, Trademarks, Copyrights and De...
WP Management Reporting Excellence_3
Ad

Similar to Scala based Lift Framework (20)

PPT
Intro lift
PDF
Lift 2 0
 
PDF
Lift talk
PDF
Lift Framework
KEY
Scala & Lift (JEEConf 2012)
PDF
Introduction to Scala for Java Programmers
PPT
Play!ng with scala
PPTX
Increase your performance and code quality
PPTX
Increase your quality and performance
PDF
Beginning Scala with Skinny Framework #jjug_ccc
PDF
Phoenix + Reactで 社内システムを 密かに作ってる
PDF
London Scala UG - Lift:Getting started with Scala
PDF
Solid And Sustainable Development in Scala
PDF
Solid and Sustainable Development in Scala
PPTX
Big Data processing with Spark, Scala or Java?
KEY
Lift Introduction
PDF
Grails and Neo4j
PDF
GR8Conf 2011: Neo4j Plugin
ODP
Large scale crawling with Apache Nutch
PDF
Cutting Edge Data Processing with PHP & XQuery
Intro lift
Lift 2 0
 
Lift talk
Lift Framework
Scala & Lift (JEEConf 2012)
Introduction to Scala for Java Programmers
Play!ng with scala
Increase your performance and code quality
Increase your quality and performance
Beginning Scala with Skinny Framework #jjug_ccc
Phoenix + Reactで 社内システムを 密かに作ってる
London Scala UG - Lift:Getting started with Scala
Solid And Sustainable Development in Scala
Solid and Sustainable Development in Scala
Big Data processing with Spark, Scala or Java?
Lift Introduction
Grails and Neo4j
GR8Conf 2011: Neo4j Plugin
Large scale crawling with Apache Nutch
Cutting Edge Data Processing with PHP & XQuery

Recently uploaded (20)

PDF
Encapsulation theory and applications.pdf
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
cuic standard and advanced reporting.pdf
PDF
Empathic Computing: Creating Shared Understanding
PPT
Teaching material agriculture food technology
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
sap open course for s4hana steps from ECC to s4
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
Spectroscopy.pptx food analysis technology
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Electronic commerce courselecture one. Pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
KodekX | Application Modernization Development
Encapsulation theory and applications.pdf
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Chapter 3 Spatial Domain Image Processing.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
cuic standard and advanced reporting.pdf
Empathic Computing: Creating Shared Understanding
Teaching material agriculture food technology
“AI and Expert System Decision Support & Business Intelligence Systems”
Unlocking AI with Model Context Protocol (MCP)
Digital-Transformation-Roadmap-for-Companies.pptx
Dropbox Q2 2025 Financial Results & Investor Presentation
Spectral efficient network and resource selection model in 5G networks
sap open course for s4hana steps from ECC to s4
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Spectroscopy.pptx food analysis technology
Understanding_Digital_Forensics_Presentation.pptx
Electronic commerce courselecture one. Pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
KodekX | Application Modernization Development

Scala based 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