The Lift Web application framework requires Scala, and Scala depends on a Java Development Kit, so you need that, too. Here is the software used in writing this article.
- Java Development Toolkit
- You need JDK V1.5 or higher for Scala. We used Java V1.5.0_13. You can also use the IBM Java 2 Platform.
- Scala
- We used Scala V2.6.1 According to the Scala Web site, the Scala software distribution is best installed on a Unix® or Windows® system. It requires V1.4 or later of the Java 2 Runtime Environment (e.g., JRE from Sun Microsystems or JRE from IBM®).
- Apache Maven
- Lift relies on Apache Maven for setting up projects, testing code, etc. You need Apache Maven V2.0.7 or later, and in this article, we used V2.0.9.
- Apache Geronimo
- Lift works best with Jetty, so we used Apache Geronimo V2.1.1 with Jetty.
- A database
- Lift uses an embedded Apache Derby database by default, but you can also use MySQL or Postgres.
Lift is written in Scala, but we won't assume too much knowledge of Scala. Familiarity with the Java language and Java Web programming is needed. Finally, familiarity with Maven will also be useful, as Lift makes heavy use of it.
Before we start talking about downloading libraries and executing scripts, we should talk about why you would want to use Lift in the first place. After all, there are countless other Web application frameworks out there that will also work just fine with Geronimo. This article will show how easy it is to create and test a Web application using Lift by covering important Lift constructs, including snippets and models.
Java Web programmers are blessed with a plethora of choices when it comes to Web frameworks. Some might even say there are too many choices, if there can be such a thing. Where does Lift fit in? Lift is written in Scala, which is not Java. However, Scala compiles to Java byte code, but this is not some kind of emulated wrapper code, like you see with many dynamic languages that run on the JVM. Scala is a statically typed language and runs as fast "native" Java. This should be no surprise because Scala's creator also wrote the Java compiler. So with Scala, you get a much more expressive language than Java, but it runs on the JVM and runs as fast as Java. These are good ingredients for a Web framework — a powerful language that lets you write less code and is high on the performance scale at the same time.
So Scala is great, but what about Lift? Lift takes great advantage of Scala. It works in any Java Web container, as it makes use of a standard Java servlet and servlet filter. Lift's snippets and models heavily exploit Scala's flexible syntax. Lift also makes Comet-style Ajax perform especially well thanks to Scala's actor-based concurrency system. Not convinced yet? Let's take a look at how easy it is to create a Web application using Lift.
The first thing any Web application framework requires is a download, right? Not with
Lift. Lift uses Maven for just about everything, and the initial setup is no different.
Before we start using Maven, however, make sure you set the SCALA_HOME environment variable. Then issue the command shown below.
Listing 1. Create a new Lift application
$ mvn archetype:generate -U -DarchetypeGroupId=net.liftweb
-DarchetypeArtifactId=lift-archetype-basic -DarchetypeVersion=0.8
-DremoteRepositories=http://scala-tools.org/repo-releases
-DgroupId=org.developerworks.lift -DartifactId=quepasa
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] org.apache.maven.plugins: checking for updates from central
[INFO] org.codehaus.mojo: checking for updates from central
[INFO] artifact org.apache.maven.plugins:maven-archetype-plugin: checking for
updates from central
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO] task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] Setting property: classpath.resource.loader.class =>
'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:generate]
[INFO] Generating project in Interactive mode
[INFO] Archetype repository missing. Using the one from
[net.liftweb:lift-archetype-basic:0.6 -> http://scala-tools.org/repo-releases]
found in catalog internal
Define value for version: 1.0-SNAPSHOT: : 0.1
Confirm properties configuration:
groupId: org.developerworks.lift
artifactId: quepasa
version: 0.1
package: org.developerworks.lift
Y: : y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating OldArchetype: lift-archetype-basic:0.8
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.developerworks.lift
[INFO] Parameter: packageName, Value: org.developerworks.lift
[INFO] Parameter: basedir, Value: /Users/michael/code/lift
[INFO] Parameter: package, Value: org.developerworks.lift
[INFO] Parameter: version, Value: 0.1
[INFO] Parameter: artifactId, Value: quepasa
[INFO] ********************* End of debug info from resources from generated POM
***********************
[INFO] OldArchetype created in dir: /Users/michael/code/lift/quepasa
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8 seconds
[INFO] Finished at: Wed May 21 21:49:56 PDT 2008
[INFO] Final Memory: 8M/14M
[INFO] ------------------------------------------------------------------------
|
The command we fed into Maven tells it to generate an application for us. This is a
common feature in application frameworks, first popularized by Ruby on Rails. In this
case, we have a few options for what kind of application skeleton to create. Each
corresponds to an archetype, and groupId, artifactId, and version uniquely identify the
archetype and, thus, the application skeleton to create. The remoteRepositories argument tells Maven what Maven repository to
use. The last couple of arguments —
groupId and artifactId
— are unique to your application. In this case, we used
org.developerworks.lift and quepasa for the values, but this is where you would put in your own values.
Further down in Listing 1, you should see a few bold lines. These are actually user prompts from Maven. It will ask you for the version of your application and the package of your application. After that, it will finish creating the application skeleton for you. When it is done, you should have a structure that looks similar to Figure 1.
Figure 1. Application structure
This is the structure of a Lift application. The /src/main is where all your Scala code
will go. This is where you find the Boot class, which
defines many of the configuration parameters of our application. Some of the things
you might normally find in an XML configuration file are, instead, found in the Boot class.
The /webapp directory is where we will put Web artifacts, such as HTML, JavaScript, and CSS. What about JSPs or their equivalent, you ask? There is none of that in Lift, and, again, this is by design. In Lift, you use XHTML files that included some extended markup that allow for Scala to inject dynamic content. That content comes in the form of snippets.
There are two more things you should take notice of in the /webapp directory. First is the WEB-INF directory. This is the classic WEB-INF you are familiar with from Java Web development. A Lift application is deployed by packing it up as a WAR file and sending it to a Java Web container — like Geronimo. Finally, notice the templates-hidden directory. This is where you put "master" templates for your application. This allows you to easily make global changes to look and feel.
Now that we have created a basic Lift application, we are ready to start adding to it. Lift takes a view-centric approach to Web development. Instead of creating models and controllers, we create views first and go from there. So let's start by adding a page to our application.
You don't need to run any scripts to create a view in Lift. Your views are just HTML files, so create a new HTML file in the /webapp directory. A simple form is shown below.
Listing 2. Simple form (update.html)
<lift:surround with="default" at="content">
<div class="heading" id="title">¿Qué pasa?</div>
<form method="POST">
<label for="update">What's going on? </label>
<input type="text" name="update"/>
<input type="submit" value="update"/>
</form>
</lift:surround>
|
The only thing special here is the lift:surround tag. Remember the hidden-templates
described in the previous section? This how it gets invoked. The lift:surround tells Lift to use a snippet called "surround." This is
a standard snippet included with Lift. It is similar to a custom tag you might find in
JSPs, at least in terms of its syntax. In this case, we are using the default template.
That will pull in all the standard HTML stuff defined in the default.html template, like
the HTML head and body tags, etc. You can change the default template or create your own
and reference it through the surround template.
There is one more thing we need to do to add our new page to the
application. We mentioned the Boot
class and how it's used to define configuration data. One of the
configurations it defines is a site map, so we need to add the
new HTML page to the site map, as shown in Listing 3.
Listing 3. Adding a page to the
Boot class' site map
package bootstrap.liftweb
import net.liftweb.util._
import net.liftweb.http._
import net.liftweb.sitemap._
import net.liftweb.sitemap.Loc._
import Helpers._
import net.liftweb.mapper.{DB, ConnectionManager, Schemifier,
DefaultConnectionIdentifier, ConnectionIdentifier}
import java.sql.{Connection, DriverManager}
import org.developerworks.lift.model._
/**
* A class that's instantiated early and run. It allows the application
* to modify lift's environment
*/
class Boot {
def boot {
if (!DB.jndiJdbcConnAvailable_?) DB.defineConnectionManager
(DefaultConnectionIdentifier, DBVendor)
// where to search snippet
LiftRules.addToPackages("org.developerworks.lift")
Schemifier.schemify(true, Log.infoF _, User)
LiftRules.addTemplateBefore(User.templates)
// Build SiteMap
val entries = Menu(Loc("Home", "/", "Home")) ::
Menu(Loc("update", "/update", "The Update Page")) ::
Nil
LiftRules.setSiteMap(SiteMap(entries:_*))
S.addAround(User.requestLoans)
}
}
object DBVendor extends ConnectionManager {
def newConnection(name: ConnectionIdentifier): Can[Connection] = {
try {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver")
val dm = DriverManager.getConnection("jdbc:derby:quepasa;create=true")
Full(dm)
} catch {
case e : Exception => e.printStackTrace; Empty
}
}
def releaseConnection(conn: Connection) {conn.close}
}
|
The site map is found in the entries value. The :: notation is used to create a list literal. As you can see, there is
already a "Home" entry that maps to "/" (the index.html page). Nil denotes the end of the list.
Now that we have added a page and added it to our site map, we are ready to test the application. Lift makes this easy.
Time to test our Lift application, so package up the code and fire up the database and the application server, right? Not so fast. Like many modern Java Web frameworks, Lift takes advantage of an embedded database (Derby) and an embedded Web container (Jetty). This lets us test our applications without any packaging or external dependencies. All we need to do is use Maven, as shown below.
Listing 4. Running Lift with Maven
$ mvn jetty:run -U
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'jetty'.
[INFO] org.apache.maven.plugins: checking for updates from scala-tools.org
[INFO] org.apache.maven.plugins: checking for updates from central
[INFO] org.codehaus.mojo: checking for updates from scala-tools.org
[INFO] org.codehaus.mojo: checking for updates from central
[INFO] artifact org.scala-tools:maven-scala-plugin: checking for updates
from scala-tools.org
[INFO] artifact org.scala-tools:maven-scala-plugin: checking for updates from central
[INFO] artifact org.mortbay.jetty:maven-jetty-plugin: checking for updates
from scala-tools.org
[INFO] artifact org.mortbay.jetty:maven-jetty-plugin: checking for updates from central
[INFO] artifact net.sf.alchim:yuicompressor-maven-plugin: checking for
updates from scala-tools.org
[INFO] artifact net.sf.alchim:yuicompressor-maven-plugin: checking for updates
from central
[INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for
updates from scala-tools.org
[INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for
updates from central
[INFO] ------------------------------------------------------------------------
[INFO] Building quepasa
[INFO] task-segment: [jetty:run]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing jetty:run
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [yuicompressor:compress {execution: default}]
[INFO] nb warnings: 0, nb errors: 0
[INFO] artifact org.mortbay.jetty:jetty: checking for updates from scala-tools.org
[INFO] artifact org.mortbay.jetty:jetty: checking for updates from central
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:compile {execution: default}]
[INFO] Compiling 2 source files to /Users/michael/code/lift/quepasa/target/classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:testCompile {execution: default}]
[INFO] Compiling 3 source files to /Users/michael/code/lift/quepasa/target/test-classes
[INFO] [jetty:run]
[INFO] Configuring Jetty for project: quepasa
[INFO] Webapp source directory = /Users/michael/code/lift/quepasa/src/main/webapp
[INFO] web.xml file = /Users/michael/code/lift/quepasa/src/main/webapp/WEB-INF/web.xml
[INFO] Classes = /Users/michael/code/lift/quepasa/target/classes
2008-05-23 21:19:31.149::INFO: Logging to STDERR via org.mortbay.log.StdErrLog
[INFO] Context path = /
[INFO] Tmp directory = determined at runtime
[INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml
[INFO] Web overrides = none
[INFO] Webapp directory = /Users/michael/code/lift/quepasa/src/main/webapp
[INFO] Starting jetty 6.1.10 ...
2008-05-23 21:19:31.245::INFO: jetty-6.1.10
2008-05-23 21:19:31.409::INFO: No Transaction manager found - if your webapp
requires one, please configure one.
2008-05-23 21:19:31.989::INFO: Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 5 seconds.
|
The first time you run this command, you will see Maven download several JARs it needs to run Jetty. Once this is done, you should be able to bring up your Lift application by going to http://localhost:8080.
Figure 2. Welcome page
If you click on Update Page, you should see the page we created earlier.
Figure 3. The update page
You might have noticed the title of the page and the links at the bottom. These all come from the default template shown below.
Listing 5. The default template
<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>Lift Web Framework</title>
<lift:CSS.blueprint />
<lift:CSS.fancyType />
<script id="jquery" src="/classpath/jquery.js" type="text/javascript"/>
<script id="json" src="/classpath/json.js" type="text/javascript"/>
<style>
/* <![CDATA[ */
.sidebar ul {
margin:0;
padding:0;
border-bottom:1px solid #ccc;
}
.sidebar ul li {
margin:0;
padding:0;
list-style:none;
border:1px solid #ccc;
border-bottom:none;
}
.sidebar ul li a {
display:block;
padding:3px;
text-indent:30px;
text-decoration:none;
}
.sidebar ul li a:hover {
background-color: #eee;
}
/* ]]> */
</style>
</head>
<body>
<div class="container">
<div class="column span-12 last" style="text-align: right">
<h1 class="alt">quepasa</h1>
</div>
<hr/>
<div class="column span-6 colborder sidebar">
<hr class="space" />
<lift:Menu.builder />
<div>
<lift:snippet type="msgs"/>
<hr class="space" />
</div>
</div>
<div class="column span-17 last">
<lift:bind name="content" />
</div>
<hr />
<div class="column span-23 last" style="text-align: center">
<h4 class="alt">
<a href="http://liftweb.net">
<i>lift</i>
</a> is Copyright 2007 WorldWide Conferencing, LLC.
Distributed under an Apache 2.0 License.</h4>
</div>
</div>
</body>
</html>
|
The Maven script we used to create the application generated the title. You can change
it in the template, and it will be picked up on all pages. The lift:Menu.builder is another Lift snippet. In this case, it is using
the site map from the Boot class to create site menu. As
you can see, snippets are quite powerful. They are the key to making Lift applications
dynamic. We have used some standard snippets included with Lift, but let's take a look at creating a custom snippet.
As mentioned, Lift is view-centric. Server-side code is executed when Lift encounters tags in the view code. With that in mind, Listing 6 shows an updated version of our view code.
Listing 6. Updated view
<lift:surround with="default" at="content">
<div class="heading" id="title">¿Qué pasa?</div>
<lift:Update.show form="POST">
<label for="update">What's going on? </label>
<qp:update/>
<qp:submit/>
<qp:messages/>
</lift:Update.show>
</lift:surround>
|
Instead of having a form, we use a Lift snippet. The lift:Update.show tells Lift we want to invoke a method called show on a class called Update. The qp:update tag output variables bound within that method.
Listing 7. The
Update snippet
package org.developerworks.lift.snippet
import scala.xml.NodeSeq
import net.liftweb.http.S._
import net.liftweb.http.SHtml._
import net.liftweb.http.RequestVar
import net.liftweb.util.Helpers._
import net.liftweb.util.Full
class Update {
object qpx extends RequestVar(Full("")) // default is empty string
def show(xhtml: NodeSeq): NodeSeq = {
val temp = if (qpx.isEmpty || qpx.open_!.length == 0) "" else "Received: "
+ qpx.open_!
bind("qp", xhtml,
"update" --> text("", v => qpx(Full(v))) % ("size" -> "10") %
("id" -> "update"),
"submit" --> submit(?("Update"), ignore => {}),
"messages" --> <div>{temp}</div>
)
}
}
|
The qpx object is a request variable. The show method is bound to the value submitted in the form. We create a
temp variable that is either an empty string or, if there is
a value submitted to the form, prefixes a Received: string
to the submitted value. The bind section binds data to each
of the tags we saw in the view. The data in this case is XML. The text and submit functions are XML
builders. For the messages tag, we use XML directly. XML is
a first-class citizen in Scala, and Lift takes great advantage of this.
To test the new code, all we need to do is recompile, and once again, we use Maven.
Listing 8. Recompiling the application
$ mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building quepasa
[INFO] task-segment: [compile]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [yuicompressor:compress {execution: default}]
[INFO] nb warnings: 0, nb errors: 0
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:compile {execution: default}]
[INFO] Compiling 1 source files to /Users/michael/code/lift/quepasa/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7 seconds
[INFO] Finished at: Fri May 23 22:21:19 PDT 2008
[INFO] Final Memory: 9M/18M
[INFO] ------------------------------------------------------------------------
|
We had to recompile because we added a new Scala class. If all we had done was change the HTML view, there would have been no need to recompile. We do not have to stop and start the server; we can just leave it run as we recompile. Now our application should look like Figure 4.
Figure 4. ¿Qué pasa? V2.0
Take a quick look at the HTML source code for this page. You will see something similar to Listing 9, although it will not be exactly the same.
Listing 9. View source excerpt
<div id="title" class="heading">¿Qué pasa?</div>
<form method="POST" action="/update">
<label for="update">What's going on? </label>
<input size="20" name="F1211607483014814000_QS4" type="text" value="" id="update" />
<input name="F1211607483015168000_TRV" type="submit" value="Update" />
<div>Received: Writing about Lift!</div>
</form>
|
Notice the obfuscated names of the form fields. This adds security to the form, as it is much harder to fake a form submission. Lift handles all of this for you. Now that we have a secure form, let's do something a little more interesting with the data being submitted from this form. To do that, we need to add a model to our application.
Back in Figure 1, you might have noticed a model directory. This is where we put model
classes in Lift, and there is already one there: User. This
is a general-purpose object model for a Web user you can use as-is, modify, or
discard. Take a look at it because it demonstrates many of the concepts in Lift's OR
mapping. We will create a new model to store updates.
Listing 10. The
Message model
package org.developerworks.lift.model
import net.liftweb.mapper._
import net.liftweb.util._
object Message extends Message with KeyedMetaMapper[Long, Message] {
override def dbTableName = "message"
override def fieldOrder = id :: text :: Nil
}
class Message extends KeyedMapper[Long, Message] {
def getSingleton = Message // what's the "meta" object
def primaryKeyField = id
object id extends MappedLongIndex(this)
object text extends MappedString(this, 1400)
}
|
Notice we have a Message class and a Message object. Anything directly declared as an object in Scala is a
singleton. The Message singleton serves as a metadata
repository and factory class for the Message class. Notice
that it extends KeyedMetaMapper object. The square brackets
denote a parameterized class in Scala, and in this case, it takes the type of the ID
and the type of the actual model class. This is a powerful construct that makes the
Message object easy to use.
The Message class simply defines two fields: id and text.
These will be mapped to the database. The types, such as MappedString, not only tell Lift how to map the field to the
database type but also provide HTML rendering for the field. Now we can use the Message model in our snippet.
Listing 11. Snippet with model
package org.developerworks.lift.snippet
import scala.xml.NodeSeq
import net.liftweb.http.S._
import net.liftweb.http.SHtml._
import net.liftweb.http.RequestVar
import net.liftweb.util.Helpers._
import net.liftweb.util.Full
import org.developerworks.lift.model.Message
class Update {
object qpx extends RequestVar(Full("")) // default is empty string
def show(xhtml: NodeSeq): NodeSeq = {
val msgSent = !(qpx.isEmpty || qpx.open_!.length == 0)
if (msgSent){
val msg:Message = Message.create
msg.text(qpx.open_!).save
}
val messages = Message.findAll
val temp = messages.foldLeft(""){(str, msg) => str + " ### " + msg.text}
bind("qp", xhtml,
"update" --> text("", v => qpx(Full(v))) % ("size" -> "10") % ("id" -> "update"),
"submit" --> submit(?("Update"), ignore => {}),
"messages" --> <div>{temp}</div>
)
}
}
|
There are two things added. First, if there is a new message being posted, we create a
new Message model and save it to the database. Next, we load
all the Messages from the database. The foldLeft construct allows us to iterate over the collection of Messages (imagine it going from left to right) and on each
iteration, replace the current expression (which starts as the empty string, the first
parameter passed to foldLeft) with the evaluation of the
closure (the second parameter passed to foldLeft). In this
case, it effectively appends the text of all of the messages together, separating them
with a ### string. Not exactly a fancy way to format the
messages, but it shows how you can use Lift's OR framework, as well as the power of Scala.
Before we recompile the application, there's one more thing that must be done. In the
Boot class, we need to tell the application that there is a
new model for the database. This will create the table in the database. It takes only
one line of code to do this.
Listing 12. Adding a model to the
Boot class
Schemifier.schemify(true, Log.infoF _, Message)
|
In the Boot class shown in Listing 13, you can see the logic
it uses to get a database connection. Lift can use a JNDI-supplied connection, using a
convention-over-configuration approach: It automatically looks for a data source bound
to the JNDI name. If there is no JNDI data source, it uses the DBVendor object to manage connections. If you want to use a database
other than the embedded Derby one, you can add the connection information here.
Now we have seen the basic functions in Lift, so let's find out how to deploy it to Geronimo.
Scala has a powerful syntax that is much more expressive than Java. Nonetheless, Scala compiles down to byte code just like Java. In fact, its byte code can be hard to distinguish from byte code created through Java source code, and its performance is on par with Java. Lift makes great use of Scala to allow for paradigms that are much different from your typical Java Web application framework. Still, Lift runs as a Java Web application. That is what is going on when using the embedded Jetty. You can also very easily create a Java WAR with Lift that can be deployed to any Web container, including Geronimo.
Before we create a WAR, we want to make it appropriate for use with Geronimo. In the webapp/WEB-INF directory, we will create a Geronimo deployment plan.
Listing 13. Geronimo deployment plan
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1">
<environment xmlns="http://geronimo.apache.org/xml/ns/deployment-1.1">
<moduleId>
<groupId>liftApps</groupId>
<artifactId>quepasa</artifactId>
<version>0.1</version>
<type>war</type>
</moduleId>
</environment>
<context-root>/quepasa</context-root>
</web-app>
|
Notice the /quepasa path; we will use that to access our application after it is deployed to Geronimo. Now we can create a WAR file using Maven.
Listing 14. Create WAR with Maven
$ mvn package
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building quepasa
[INFO] task-segment: [package]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [yuicompressor:compress {execution: default}]
[INFO] nb warnings: 0, nb errors: 0
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:compile {execution: default}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [scala:testCompile {execution: default}]
[INFO] Nothing to compile - all classes are up to date
[INFO] Surefire report directory: /Users/michael/code/lift/
quepasa/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.developerworks.lift.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.039 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] [war:war]
[INFO] Packaging webapp
[INFO] Assembling webapp[quepasa] in [/Users/michael/code/lift/
quepasa/target/quepasa-0.1]
[INFO] Processing war project
[INFO] Webapp assembled in[811 msecs]
[INFO] Building war: /Users/michael/code/lift/quepasa/target/quepasa-0.1.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 31 seconds
[INFO] Finished at: Sun May 25 23:02:08 PDT 2008
[INFO] Final Memory: 13M/23M
[INFO] ------------------------------------------------------------------------
|
When you run this command for the first time, there will be several JARs downloaded. Now that the WAR has been created, it is ready to be deployed to Geronimo.
Deploying an application to Geronimo is easy to do, and this is no different when using a Lift Web application. You can use the Geronimo console, shown in Figure 5.
Figure 5. Geronimo console
Use the Archive > Browse button to navigate to the WAR file that Maven created in Listing 14 and install the application. When it is installed, you should be able to go to http://locahost:8080/quepasa, as shown below.
Figure 6. Lift running on Geronimo
Everything will work just like it did during testing. From here, you can customize the application more, adding more pages, models, etc. You can customize its look and feel by changing the master template. You can also integrate more with Geronimo by creating a database pool bound for Lift to use.
This article has shown you how to get up and running with Lift. We have seen all of the essential parts of Lift: its bootstrap class, views, snippets, and models. We have seen how to use them together with Lift's view-first approach to Web application. And we saw how easy it is to deploy a Lift application to Geronimo, where we can take advantage of the many benefits offered by Geronimo. There is a lot we can do already, and Lift is still very young. Keep your eyes on it as it matures and take advantage of it when you can.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample code | os-ag-lift-quepasa.zip | 12KB | HTTP |
Information about download methods
Learn
-
Read "The busy Java
developer's guide to Scala: Functional programming for the object oriented" for an introduction to Scala.
-
"The busy
Java developer's guide to Scala: Class action" explains how to use Scala's operators
as functions in your own classes.
-
Check out "The busy Java
developer's guide to Scala: Don't get thrown for a loop!" to familiarize yourself with the power of Scala's control constructs.
-
Read "Scala and
XML" to find out how Lift takes advantage of Scala's native XML support.
-
The best place for Scala information and documentation is Scala-lang.org.
-
Visit the Lift wiki for more
information.
-
Much of Scala's XML support was written by Burak Emir. Read his online book on XML.
-
Read "Develop a
simple Web application with Apache Wicket and Apache Geronimo" to learn about using Wicket with Geronimo.
-
Groovy is another promising language that compiles to Java byte code. Read about
creating XML with it in "Practically Groovy: Mark
it up with Groovy Builders."
-
You can learn more about data binding frameworks (included JiBX) by reading Dennis
Sosnoski's series on "XML and Java
technologies."
-
Learn about the structure of a DOM document, how to use Java technology to create a
document from an XML file, make changes to it, and retrieve the output in "Understanding DOM."
-
To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
-
Stay current with developerWorks' Technical events and webcasts.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
-
Scala is a general purpose programming language designed to express common programming
patterns in a concise, elegant, and type-safe way.
-
Java technology is a programming language and a
platform. Download the Java Development Kit (JDK) from Sun Microsystems or from IBM.
-
Maven, an Apache project, is a software
project-management and comprehension tool.
-
Geronimo, an Apache project, is a server
runtime framework that pulls together open source alternatives to create runtimes that
meet the needs of developers and system administrators.
-
Apache Derby, an Apache DB subproject, is an
open source relational database implemented in Java.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
-
Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
-
Participate in developerWorks blogs and get involved in the developerWorks community.






