In this chapter, we will learn how to install Lift, which is a very secure web framework written in Scala; how to configure the basics of a Lift application such as how to define the SiteMap which is a comprehensive representation of the pages of a Lift application; and how to configure a log engine. We will also learn how to create an application using Simple Build Tool (SBT) or Maven.
SBT is a build tool for Scala and Java projects. The idea of using a build tool such as SBT is to make it easier to manage all of the project dependencies. Also, it helps to ensure that the application generated by the build process is always the same. This means that it doesn't matter whether the application is built on my computer or yours, the end result will be the same.
The easiest way to start with Lift and SBT is by downloading them from the official website. There, you can find a list of tar.gz
and .zip
files containing everything you need to start using Lift.
Scala, and in turn, the Lift development requires a JVM and because of this, you'll need to install Java 7 on your computer. However, you can skip this step if you already have it installed. If not then go to http://java.com and click on the Free Java Download button. Then, download and install the JDK appropriate for your OS.
Carry out the following steps:
First of all, to install and run Lift on Windows, you will need to download the
Lift 2.5
ZIP file, which is the latest stable release, from http://liftweb.net/download.After the download is complete, open Windows Explorer and extract the contents from the file.
Then, go to
scala_210/ift_basic
, double click on thesbt.bat
file to run SBT, and wait until SBT finishes downloading the required libraries. This process can take a while depending on the speed of your internet connection.When the download part is completed, you will get the SBT prompt that can be recognized by the
>
character.After getting into the SBT prompt, type the following command to start the basic Lift application:
> container:start
At this point, we have a running Lift application. So, open up your favorite browser and go to
http://localhost:8080
. Then you should see a welcome window similar to the following screenshot:To exit SBT, you just need to type the following command in the SBT prompt:
> exit
The ZIP file contains some examples of Lift applications such as a blank application that you can use to start your application from scratch. It also contains a basic Lift application that contains Blueprint CSS and ready-to-use Mapper models, which you can use as the start point when building your own application.
The lift_basic
folder contains a working Lift application. This means that you have SBT and a configured, ready-to-use project in it.
When we ran SBT, it started to download all the required libraries that the application needs (these dependencies are defined in the build.sbt
file). Once this step is done, we can start the application.
After downloading the required libraries, we ran the
container:start
command provided by the sbt-web-plugin that deploys the Lift application into an embedded Jetty server.
You can see that inside the lift_basic
application, there is a folder called project
which contains a file called project.sbt
. In that file, you will see that it defines three plugins for SBT. The first defined plugin is the XSBT plugin. After the XSBT plugin, there is the sbt-idea plugin and the sbteclipse plugin. The former is to enable SBT to be integrated with IntelliJ IDEA, and the latter enables SBT to be integrated with Scala IDE. Another thing to notice in the plugins.sbt
file is that it matches the version of SBT to select the correct version of the sbt-web-plugin.
To install and run Lift on Linux or Mac, perform the following steps:
Download the
Lift 2.5 ZIP
or thetar.gz
file from http://liftweb.net/download.Once you've got the file, open a shell tool and expand it.
Then, go to
scala_210/lift_basic
, and start SBT by running the following command:./sbt
You can then continue from step 4 of the How to do it… section.
You can read the
README.md
file and explore each sample application folder to learn more about what is bundled within Lift's ZIP fileYou can find more about the sbt-web-plugin at the following URL: https://github.com/JamesEarlDouglas/xsbt-web-plugin
Please navigate to https://github.com/mpeltonen/sbt-idea to get to know more about the SBT plugin for IntelliJ IDEA
Please navigate to https://github.com/typesafehub/sbteclipse to learn more about the SBT plugin for ScalaIDE/Eclipse
To find more about SBT, please go to http://www.scala-sbt.org/
In the previous recipe, we learned how to use SBT to create and run a Lift application. Now I will show you how to set up and run a Lift application using Maven, which is another build tool.
If you don't have Maven installed and configured on your computer, go to http://maven.apache.org/download.cgi, download Maven 3.1.0, and follow the installation instructions.
We will use a Maven archetype that will create a ready-to-use Lift application for us.
Open a cmd window and run the following command:
mvn archetype:generate ^ -DarchetypeGroupId=net.liftweb ^ -DarchetypeArtifactId=lift-archetype-basic_2.9.1 ^ -DarchetypeVersion=2.5 ^ -DarchetypeRepository=https://oss.sonatype.org/content/repositories/releases ^ -DgroupId=lift.cookbook ^ -DartifactId=chap01-mvn ^ -Dversion=1.0
After running the previous command, Maven will start to download all the required libraries to create the project.
Once the download is complete, Maven will ask you to confirm some information about the project. Confirm them by typing
Y
and pressing return.Change the following tags in the
pom.xml
file:From:
<scala.version>2.9.1</scala.version>
To:
<scala.version>2.10</scala.version>
From:
<artifactId>lift-mapper_2.9.1</artifactId>
To:
<artifactId>lift-mapper_2.10</artifactId>
From:
<artifactId>lift-jquery-module_2.9.1</artifactId> <version>2.5-2.0</version>
To:
<artifactId>lift-jquery-module_2.5_2.10</artifactId> <version>2.4</version>
From:
<groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <version>2.15.2</version>
To:
<groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <version>3.1.5</version>
From:
<groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.26</version>
To:
<groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId>
When you have finished editing the
pom.xml
file, open a cmd window, go to the folder containing thepom.xml
file, and run the following command to update and compile the project:mvn compile
Once Maven finishes the compilation, you will be able to start the application by running the following command:
mvn jetty:run
Now that you have the application up and running, you can access
http://localhost:8080
in your favorite browser, and you should see a welcome page similar to the following:
When you create a project using the Lift archetype, you get a fully working application containing everything you need to build your own application. This means that Maven will create an application with its default directory structure, a pom.xml
file, with everything needed by the sample application. It will also include the jetty plugin that will allow us to run the application by running the jetty:run
command.
The application created by Maven is a sample application that contains Blueprint CSS and a Mapper model. One more thing to notice is that this archetype also includes plugins for IntelliJ IDEA and Scala IDE.
To learn more about Maven, please go to http://maven.apache.org/.
Lift offers several ways for programmers to define which pages their applications will have. SiteMap is one of these ways. Besides defining the pages of your application, you can also control the access of each URL. This means that you can, for example, control whether a URL will have access restrictions or not and even control the restriction level of any given URL.
What does this mean? This means that you can think of SiteMap as the defined structure of your application containing every URL that will be accessible and the policies that are applied for each one of them.
Another thing that SiteMap does is automatic mapping between URLs and XHTML templates.
In this recipe, we will see how to configure SiteMap for a simple application. For this, let's suppose we want to create an application to store and manage contacts.
We will need one URL for each of the following actions:
List contacts
Create contacts
Edit contacts
Delete contacts
View contacts' details
Copy the contents of the lift_blank
folder from the scala_29
folder to a new directory called contacts-app
.
Carry out the following steps:
Edit the
Boot.scala
file by adding a function,LocParam
, just before the declaration of theentries
value:val canManage_? = If(() => { true }, () => RedirectResponse("/"))
This is to verify whether the user accessing the URL has management permission and is allowed to access it.
Then, add another
LocParam
to check whether the user has administrative privileges:val isAdmin_? = If(() => { false }, () => RedirectWithState("/contacts/list",MessageState("Authorized personnel only" -> NoticeType.Warning)))
After creating the functions, we'll define SiteMap by adding new menu items between the
Menu.i("Home") / "index"
and theMenu(Loc("Static", …
entries.Menu items that need to be added are as follows:
Menu.i("List Contacts") / "contacts" / "list", Menu.i("Create") / "contacts" / "create" >> canManage_?, Menu.i("Edit") / "contacts" / "edit" >> canManage_?, Menu.i("Delete") / "contacts" / "delete" >> isAdmin_?, Menu.i("View") / "contacts" / "view" >> canManage_?,
Create a folder called
contacts
inside thewebapp
folder.Create five HTML files, one for each menu item defined in SiteMap:
list.html
create.html
edit.html
delete.html
view.html
Then run the application and go to the URL
http://localhost:8080
in your browser. The following screen will be displayed:
Lift will build the SiteMap object during the application boot process as a result of the invocation of the method, LiftRules.setSiteMap
.
When a user tries to access, for example /contacts/list
, Lift will use SiteMap to decide whether the resource is defined or not by matching the URL against the link list defined by the menu entries in SiteMap. Since we've defined it, Lift will serve the page to the user. However, if the user tries to access /contacts/lists
, the match will fail and Lift will return a 404 error.
We still need to understand what the LocParam
functions are that were mentioned in steps 1 and 2. LocParam
is something that modifies how Lift handles the given entry of SiteMap. In our case, it is a function that redirects the user to a different URL if the condition being tested fails. So, if someone tries to access /contacts/create
, Lift will execute the canManage_?
function after matching the URL. If the function returns true
, Lift will serve the page to the user; otherwise, it will redirect the user to /
. The same logic applies to the view and edit URLs.
The same logic applies to the delete link; the only difference being the fact that the isAdmin_?
function not only redirects the user to /
, but also passes a message that will be displayed in the page. This happens because we've used If LocParam
that takes two arguments. The first is a test function. If it returns true
, the page can be accessed; and if the return value is false
, the result of evaluating the second parameter, FailMsg
, will be sent to the browser.
The entries
variable is a list of menu items that will be processed when the application is started by Jetty.
Each menu item has a structure as shown in the following image.
Unique identifier
Link object
Text
Parameters
The unique identifier is used by Lift to keep a track of all the menu entries in SiteMap.
The Link contains the list that will be used to match the requested URL to check if it is defined or not.
The match head
parameter, which is a Boolean value, defines whether Lift will match the exact URL or everything beginning with the given path. Notice that if you pass true
, Lift will serve URLs containing /contacts/create
or /contacts/create/*
, where *
is any HTML file existing inside webapps/contacts/create
. If no such folder exists, Lift will return a 404 error. If you pass false
, Lift will only serve /contacts/create
and will return the 404 error for any other URL containing /contacts/create
.
The URL that will be used to create the link on the page will be the value rendered in the href
attribute of the anchor tag, <a href={url}>...</a>
.
text
is the text that will be shown when the link is displayed.
The parameters are functions, LocParam
, that you want to execute when rendering the link or accessing the page.
Lift comes with several types of the LocParam
functions, such as MenuCssClass
to add a CSS class to the Menu and Title
to define the title of the page.
To learn more about SiteMap, Menu, and the LocParam
functions, please go to https://www.assembla.com/wiki/show/liftweb/SiteMap.
Logback is a log engine that is intended to be a better version of the popular log4j. You might want to check the project website to understand the reasons you should consider Logback over log4j. But, you might ask why we need a log engine at all?
Logging is a useful tool that allows us to track what happens with the applications we build that are running on environments which we, as developers, cannot easily debug. That's why it is important that the tools we use to build applications support logging in an easy way. Lift does support logging in an easy and flexible manner. So, let us see how to log and what happens with our application.
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
Don't worry if you don't fully understand the following code. We will get back to it later in the book.
Create a new Scala class called
ListUser
inside the snippet package with the following code:class ListUser extends Logger { def log(text: String) { text match { case str if str.length == 0 => error("user with no name") case str if str == "Forbidden" => warn("this user shouldn't have access") case str => debug("User name: " + str) } } def list = { val users = List("John", "Sarah", "Peter", "Sam", "","Forbidden") info("listing users") "li .name *" #> users.map { user => { log(user) Text(user) } } } }
Add the following HTML snippet in
/webapp/contacts/list.html
:<ul data-lift="ListUser.list"> <li class="name"><!-- user names will be in here --></li> </ul>
Change the
code.snippet
logger insrc/main/resources/logback.xml
to debug the level as follows:<logger name="code.snippet" level="debug" />
Start the application and go to
http://localhost:8080/contacts/list
in your browser.In your browser, you will see, a page similar to the one shown in the following screenshot:
In the SBT console, you will see a log similar to the following screenshot:
We configured the log in the logback.xml
file. You might notice that there was an appender already configured. Appenders are the components that actually do the task of writing log events. There are several types of appenders and one of them is the ConsoleAppender that just prints the log entries in the standard output—the console in this case.
The class ListUser
is a Lift snippet that traverses the list of strings defined by variable users. For each string, it does two things:
Invokes the
log
methodAdds the string inside the
li
tag
Then it returns the modified HTML to be rendered in the browser.
The log
method will create a log entry with different log levels depending on the string's content, by invoking the method from the Logger
trait which includes info
, debug
, error
, warning
, and so on.
The Logger
trait's methods are accessible from the snippet because we mixed them in our snippet by extending them using extends Logger
. Then the snippet is invoked by the instruction ListUser.list
that we added in the data-lift
attribute in the HTML file.
When you use the Logger
trait, Lift will create one logger per class or object. That is why we can see the object or class where the log entry was created. You can see in our example that the log was created by the ListUser snippet by extending the trait.
This is a nice feature since we can have more control of how our application creates the log entries. We can, for example, set packages with different log levels. As you can see in the logback.xml
file, the code.snippet
has the debug level while net.liftweb
has the warn level and bootstrap.liftweb
has the info level.
Logback is not the only log engine available. If you want to use log4j, you will need to change the dependency in the build.sbt
file from:
"ch.qos.logback" % "logback-classic" % "1.0.6",
To:
"org.slf4j" % "slf4j-log4j12" % "1.6.1",
Also, you will need to create src/main/resources/log4j.xml
, which is log4j's configuration file.
You can find more about log4j at the following URL:
Check this URL if you want to learn more about Logback:
At last, you can find more information about other ways to use Lift's log engine, such as how to create a singleton logger object for the entire application, as shown here:
It does not matter if you are building your company website, an application that will be used only inside the company you work at, or an e-commerce solution. Eventually, you will need to send e-mails. It is fair to say that every web application has the need, at some point, to send e-mails.
In this recipe, we will learn how to send plain text e-mails using Gmail's SMTP server.
You can use the code of the examples we have used in the previous recipe, or you can start a new project.
Carry out the following steps:
You will need to add the following properties into
src/main/resources/default.props
:mail.user=your_email@gmail.com mail.password=your_password
Change the
mail.user
andmail.password
properties to match your Gmail account.Then create a method in the
Boot
class to configure theMailer
object as follows:def configureMailer() { import javax.mail{PasswordAuthentication, Authenticator} System.setProperty("mail.smtp.starttls.enable", "true") System.setProperty("mail.smtp.ssl.enable", "true") System.setProperty("mail.smtp.host", "smtp.gmail.com") System.setProperty("mail.smtp.auth", "true") Mailer.authenticator = for { user <- Props.get("mail.user") pass <- Props.get("mail.password") } yield new Authenticator { override def getPasswordAuthentication = new PasswordAuthentication(user, pass) } }
Then, you need to call the
configureMailer
method from within theboot
method:def boot { // where to search snippet LiftRules.addToPackages("code") configureMailer() …. }
Now, we have the
Mailer
object configured, and we are ready to send e-mails.Inside the lib package
src/main/scala/code/
, create an object calledSendEmail
that will be responsible for sending e-mails:import net.liftweb.util.Mailer import net.liftweb.util.Mailer._ object SendEmail { def send_!(from: String, recipient: String, subject: String, body: String) { val mailTypes = List(PlainMailBodyType(body), To(recipient)) Mailer.msgSendImpl ( From(from), Subject(subject), mailTypes) } }
At last, we will create a snippet to render a link to send e-mails when clicked. For this, you will need to create a class called
EmailSnippet
inside the snippet package,src/main/scala/code/
:import net.liftweb.http.SHtml import net.liftweb.util. Helpers._ import code.lib.SendEmail import xml.Text import net.liftweb.util.Props class SEmail { def sendNow() = { SendEmail.send_!( Props.get("mail.user").get, "to_email@example.com", "Sending e-mail using GMail", "Here is the body content." ) } def sendEmail = { "*" #> SHtml.link("#", () => sendNow(), Text("Send e-mail")) } }
Change
to_email@example.com
to match your Gmail account.You will also need to create the following menu item in the entries list, just after the index entry:
Menu.i("Send Email") / "send"
Create a file called
send.html
insidesrc/main/webapp
as follows:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta content="text/html; charset=UTF-8" http-equiv="content-type"/> <title>Home</title> </head> <body class="lift:content_id=main"> <div id="main" class="lift:surround?with=default;at=content"> <h2>Sending e-mail using GMail's SMTP server.</h2> <p> <span data-lift="EmailSnippet.sendEmail"><!-- there will be a button here --></span> </p> </div> </body> </html>
Start the application and go to
http://localhost:8080/send
.You should see a page containing a link called Send e-mail, similar to the following screenshot:
Click on the link to send the email, and you will receive an email in your Gmail inbox.
First of all, we have set a few mail properties that will be used by the Java Mail API, such as mail.smtp.ssl.enable
and mail.smtp.starttls.enable
. These properties will enable SSL and TLS, meaning that we will use a secure channel to send the e-mail, and mail.smtp.host
to set the SMTP server address. Then, we set mail.smtp.auth
to true
to use the SMTP authentication.
The next thing we did was to create an authenticator to use the
Mailer
object.
When creating the authenticator, we used the Props
object to get the user and password values from the default.props
file.
Then, we created the EmailSnippet
class that creates a link which when clicked, invokes the sendNow()
method. This method has no parameters and calls the SendEmail's send_!
method, passing information such as from
, to
, subject
, and body
that will be used to send the e-mail. We had to wrap the call to send_!
to keep the code easy to read. Then SendEmail's send_!
invokes Mailer
object's sendMail
method, which is the method that will send the e-mail.
Why did we do all of this in the Boot
class? Well, we just needed to configure the Mailer
object once. This is because it's a singleton, which means that only one instance of the object will be created, and we can use it throughout the application once it is configured. So, Boot
is the perfect place to do this, since it is called only once when the server, in our case Jetty, is starting the application.
Note that we configured the Mailer
object in a programmatic way. However, if you want to use The Java Naming and Directory Interface (JNDI) to configure the Mailer
object, you will need to do two things.
Note
By using JNDI to configure the Mailer
object, you can rely on the fact that the configurations will be set on the server; your application only needs to know the JNDI name to be able to use a given resource. This means that if you need to change the application server where your application will run, you won't have problems with different settings causing your application to break.
First you need to call the following code instead of using the
configureMailer()
method:Mailer.jndiName = Full("mail/Session")
Second, you need to configure the server to provide a mail session via JNDI. You do this by creating a file called
jetty-env.xml
inside theWEB-INF
folder:<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <New id="mail" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg>mail/Session</Arg> <Arg> <New class="org.eclipse.jetty.jndi.factories.MailSessionReference"> <Set name="user">your_email@gmail.com</Set> <Set name="password">your_password</Set> <Set name="properties"> <New class="java.util.Properties"> <Put name="mail.transport.protocol">smtp</Put> <Put name="mail.smtp.host">smtp.gmail.com</Put> <Put name="mail.smtp.auth">true</Put> <Put name="mail.smtp.starttls.enable">true</Put> <Put name="mail.smtp.ssl.enable">true</Put> <Put name="mail.debug">true</Put> </New> </Set> </New> </Arg> </New> </Configure>
You can get more information about the Mailer objects at the following addresses: