Skip to main content

Give Apache Geronimo a Lift

Create a Web application in Lift and deploy to Geronimo

Michael Galpin's photo
Michael Galpin has been developing Java software professionally since 1998. He currently works for eBay. He holds a degree in mathematics from the California Institute of Technology.

Summary:  Lift is a new Web application framework. It is a highly scalable framework built on the Scala programming language. It is the perfect partner for a highly scalable application server, such as Apache Geronimo, especially since Scala compiles to byte code just like the Java™ language and leverages the Java platform. In this article, you will learn how to create a Web application using Lift and deploy it to Geronimo.

Date:  22 Jul 2008
Level:  Intermediate
Activity:  2181 views

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.

Why Lift

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.


Creating a Lift application

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
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.

Adding a page

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.

Testing the application

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
Welcome page

If you click on Update Page, you should see the page we created earlier.


Figure 3. The update page
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.

Using a 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
Que 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.

Adding a model

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.


Deploying 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.

Creating a WAR

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 the WAR

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
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
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.


Summary

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.



Download

DescriptionNameSizeDownload method
Sample codeos-ag-lift-quepasa.zip12KB HTTP

Information about download methods


Resources

Learn

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

About the author

Michael Galpin's photo

Michael Galpin has been developing Java software professionally since 1998. He currently works for eBay. He holds a degree in mathematics from the California Institute of Technology.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=321216
ArticleTitle=Give Apache Geronimo a Lift
publish-date=07222008
author1-email=mike.sr@gmail.com
author1-email-cc=cappel@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers