3.1 Starting at the beginning: Boot.scala
When your Lift application first starts up, it executes the code in Boot.scala:
Boot.scala
package bootstrap.liftweb
import net.liftweb._
import util._
import Helpers._
import common._
import http._
import sitemap._
import Loc._
import code.snippet._
/**
* A class that's instantiated early and run. It allows the application
* to modify lift's environment
*/
class Boot {
/**
* Calculate if the page should be displayed.
* In this case, it will be visible every other minute
*/
def displaySometimes_? : Boolean =
(millis / 1000L / 60L) % 2 == 0
def boot {
// where to search snippet
LiftRules.addToPackages("code")
// Build SiteMap
def sitemap(): SiteMap = SiteMap(
Menu.i("Home") / "index", // the simple way to declare a menu
Menu.i("Sometimes") / "sometimes" >> If(displaySometimes_? _,
S ? "Can't view now"),
// A menu with submenus
Menu.i("Info") / "info" submenus(
Menu.i("About") / "about" >> Hidden >> LocGroup("bottom"),
Menu.i("Contact") / "contact",
Menu.i("Feedback") / "feedback" >> LocGroup("bottom")
),
Menu.i("Sitemap") / "sitemap" >> Hidden >> LocGroup("bottom"),
Menu.i("Dynamic") / "dynamic", // a page with dynamic content
Param.menu,
Menu.param[Which]("Recurse", "Recurse",
{case "one" => Full(First())
case "two" => Full(Second())
case "both" => Full(Both())
case _ => Empty},
w => w.toString) / "recurse",
// more complex because this menu allows anything in the
// /static path to be visible
Menu.i("Static") / "static" / **)
// set the sitemap. Note if you don't want access control for
// each page, just comment this line out.
LiftRules.setSiteMapFunc(() => sitemap())
//Show the spinny image when an Ajax call starts
LiftRules.ajaxStart =
Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)
// Make the spinny image go away when it ends
LiftRules.ajaxEnd =
Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)
// Force the request to be UTF-8
LiftRules.early.append(_.setCharacterEncoding("UTF-8"))
// Use HTML5 for rendering
LiftRules.htmlProperties.default.set((r: Req) =>
new Html5Properties(r.userAgent))
}
}
Rather than keeping configuration parameters in XML files, Lift keeps configuration parameters in code in Boot. Boot is executed once when the servlet container loads the Lift application. You can change many of Lift’s execution rules in the LiftRules singleton during boot, but after boot, these parameters are frozen.
3.1.1 LiftRules rules
Most of the configuration parameters that define how Lift will convert an HTTP request into a response are contained in the LiftRules singleton. Some of the parameters for LiftRules are used commonly and some are very infrequently changed from their default. LiftRules can be changed during boot, but not at other times. So, set all your configuration in boot (or in methods that are called from boot).
3.1.2 Properties and Run modes
While many properties for your running application can be defined in Boot.scala, there are some properties that are best defined in a text file. Lift supports multiple properties files per project. The properties files are loaded based on the user, machine and run mode.
If you want to provide a configuration file for a subset of your application or for a specific environment, Lift expects configuration files to be named in a manner relating to the context in which they are being used. The standard name format is:
modeName.userName.hostName.props
examples:
dpp.yak.props
test.dpp.yak.props
production.moose.props
staging.dpp.props
test.default.props
default.props
with hostName and userName being optional, and modeName being one of "test", "staging", "production", "pilot", "profile", or blank (for development mode). The standard Lift properties file extension is "props".
Place properties files in the src/main/resources/props directory in your project and they will be packaged up as part of the build process.
When you’re developing your Lift application, the run mode (see net.liftweb.util.Props.mode) will be Development. When you deploy your application, pass -Drun.mode=production to your web container. In production mode, Lift aggressively caches templates, snippet classes, etc.
3.1.3 By convention
Lift, like Rails, will look for items in certain locations by convention. For example, Lift will look for classes that implement snippets in the xxx.snippet package where the xxx part is the main package for your application. You define one or more packages for Lift to look in with:
// where to search snippet
LiftRules.addToPackages("code")
Here, we’ve added the code package to the list of packages that Lift will search through. You can also do LiftRules.addToPackages("com.fruitbat.mydivision.myapplication").
3.1.4 Misc Rules
We’ll skip the sitemap definition until the next section. This rule defines how to show a spinning icon during Ajax calls (Lift will automatically show the spinning icon if this function is enabled):
//Show the spinny image when an Ajax call starts
LiftRules.ajaxStart =
Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)
And this rule sets the default character encoding to UTF-8 rather than the default platform encoding:
// Force the request to be UTF-8
LiftRules.early.append(_.setCharacterEncoding("UTF-8"))
Okay... you get the idea... there are plenty of parameters to tune during boot.
Prior to Lift 2.2, Lift treated all templates as XHTML and emitted XHTML to the browser. When the Lift project started in early 2007, this seemed like a Really Good Idea™. Turns out the world has not adopted XHTML and some JavaScript libraries, e.g. Google Maps, doesn’t work on XHTML pages. Lift 2.2 introduced optional Html5 support both in the parser (so it could read Html5 templates rather than requiring well formed XML in templates) and emits Html5 to the browser. Lift still processes pages as Scala NodeSeq elements, so no changes are required to the application.
In order to keep Lift 2.2 apps backward compatible with Lift’s XHTML support, by default the XHTML parser/serializer are used. However, it’s recommended to use the Html5 support which can be turned on in boot with:
// Use HTML5 for rendering
LiftRules.htmlProperties.default.set((r: Req) =>
new Html5Properties(r.userAgent))
(C) 2012 David Pollak