Background
You can tell from my blog posts that I like Scala. I have wanted to try out Liftweb for a while, but was turned off by the apparent requirement of using Maven. I figure that if I do like Lift, it will be enough work to convince my company that they should switch to Scala and Lift without also having to convince them at the same time that they should switch to Maven.The members of the Lift community seem pleased with Maven and are not interested in supporting a non-Maven workflow. It's not that Lift requires Maven - in fact, David really wants people to know that Lift does not require Maven - but at the moment it's simply not a priority for them to support a non-Maven download. Although you can't really fault a newcomer for thinking that Maven is required, given that the Getting Started page currently states that Maven 2 is a "prerequisite". If you start asking about downloading and using Lift without Maven you tend to get a lot of responses about how great Maven is and how you should really try it. This is perhaps unfortunate, because many people, myself included, are not looking for a discussion about Maven and really want to minimize the number of new tools and workflow changes necessary just to try out a piece of software. Maven may be great, but that's not what I want to hear about right now. So I decided to figure out for myself just what it would take to download, compile and run Liftweb without Maven.
I started by using the standard Maven-based approach to get the files onto my machine, then hacked until I had what I wanted. You can do the same thing (it was actually pretty easy), or if you are having trouble with Maven or you simply don't want to touch it yet, you can use the directions I give below on how to download and set up the Liftweb demo without it. So although the semi-official answer (on the Lift wiki) to how to use Lift without Maven is that you at least need to use Maven to download the initial lift project, I'm here to tell you that you can download, compile and run the demo Lift app without using Maven at all.
With Maven
The download page on the Lift web site is interesting. There is a short paragraph for each of Mac, Windows and Linux downloads. The Mac and Windows paragraphs each include a link to a download package. The Linux paragraph just says, if you have trouble, ask someone on the mailing list.I scratched my head a bit at the lack of a download link on the Download page, but finally went back to the main page, saw the link to the Getting Started page, opened the HTML document there, and started reading how to install Liftweb.
Step 1 is to run the
mvn archetype:generate
command,
which downloads the Lift templates that Maven uses to build and update Lift.
Unfortunately, those Lift templates
require version 2.0.9 of Maven,
and the newest version available as a standard package on my system
(Fedora 9)
is Maven 2.0.4.
Rather than upgrading my OS,
I went to the Maven website,
downloaded the latest version
of Maven (2.1.0), and installed it in an alternate location on my system.
I then updated my $PATH to include that alternate
location so that I would be using a new enough version of Maven
to work on the Lift demo.
After downloading and installing the updated version of Maven, I was able to run the
mvn archetype
command listed on
the Getting Started page.
Since I had not used Maven before on this computer, it downloaded
a bunch of files - about 5MB worth.
The Getting Started page does say Maven will output
"several page's worth of text", so this was not entirely a surprise.
Step 2 is to run the
mvn jetty:run
command.
This command finishes building the demo Liftweb app and starts it
using Jetty listening on port 8080.
When I ran this second Maven command, it downloaded
another big batch of files from the Internet.
The Getting Started page says that after the first step,
"you've now successfully created your first project",
and it just says the second step "should produce more output",
implying that there is not much work to be done in that second step.
However, the second step took at least 5 times as long and downloaded
another 30 MB of files; that was a bit of a surprise.
In total Maven took about four minutes and downloaded 35MB of files -
710 files, including 82 jar files -
into my new $HOME/.m2
directory (the Maven cache),
including older versions of
Scala and Ant than I already had on my machine.
That's not really all that much time or space for a modern computer,
but it was perhaps a bit more than I was expecting would be required
for a "hello world" program.
And in fact, as you will see
below, only a small part of those files
are necessary.
Unfortunately, after downloading half the Internet and finishing the build of the Liftweb demo, it failed to run on my system. Ah, but of course: I am already running Tomcat, which is using port 8080, the same port the Liftweb demo was trying to use. No problem, I thought, I will just change the port that the Liftweb demo uses. Unfortunately, my quick attempt was unsuccessful. I searched through all the files for 8080, found it in one place, changed it to 8181, then ran
mvn jetty:run
again.
No luck - after crunching for about ten seconds
it still tried to open port 8080.
Among the many messages that Maven spit out was the line
"Nothing to compile - all classes are up to date",
so apparently it did not notice that I had edited one of the source files.
Well, no big deal, I just stopped Tomcat for a while and tried it again,
and I was able to access the demo web page at localhost:8080.
So getting the Liftweb demo running using the Maven approach was pretty easy:
- Download and install a new version of Maven.
- Stop Tomcat on my machine.
- Run the two maven commands on the Liftweb Getting Started page.
- Open my web browser to
http://localhost:8080
and view the hello world page.
Without Maven
As you can see from the above, getting Lift downloaded and working with Maven was, for me, no problem. But what I really wanted to do was to build a war file that I could drop into my already-running Tomcat. I started with a simple ant script to compileHelloWorld.scala
,
and kept adding bits and pieces to it until I was able to
build a working war file.
Below are the details about the final setup I used
to create a war file that worked under Tomcat.
I am using a grand total of 11 files:
- Two scala files:
Boot.scala
andHelloWorld.scala
- Two html files:
index.html
andtemplates-hidden/default.html
- Two xml files:
web.xml
andbuild.xml
- Five jar files:
lift-util.jar
,lift-webkit.jar
,scala-library.jar
,log4j.jar
, andcommons-fileupload.jar
web.xml
and
the two lift jar files came unmodified out of the Liftweb demo,
the Scala library came from the standard Scala download,
the other two jar files were standard downloads from Apache, and
the one file I created myself was the ant build file build.xml
.
My directory hierarchy looks like this:
The five library jar files are stored elsewhere in my system and are copied in to the build directory when the war file is being created. You could create aliftdemo/ build/ All generated files go here build.xml Ant build file src/ scala/ bootstrap/liftweb/Boot.scala demo/helloworld/snippet/HelloWorld.scala webapp/ index.html web.xml templates-hidden/default.html
lib
directory in the liftdemo
directory and drop the libraries in there if you wanted to.
If you used Maven to download Lift, you can pull all of these
libraries from your $HOME/.m2
Maven cache,
else you can download them from their internet homes
if you don't already have them somewhere on your system.
The war file
liftdemo.war
looks like this:
You can download files directly from the Liftweb Maven repository without using Maven: use these direct download links for the demo sources packed in a jar file,META-INF/MANIFEST.MF WEB-INF/ web.xml classes/ bootstrap/liftweb/ Boot$$anonfun$1.class Boot.class demo/helloworld/snippet/HelloWorld.class lib/ commons-fileupload-1.2.1.jar lift-util-1.0.jar lift-webkit-1.0.jar log4j-1.2.14.jar scala-library.jar index.html templates-hidden/default.html
lift-util-1.0.jar
,
and lift-webkit-1.0.jar
.
(Note that these are all version 1.0 files, so if you are reading this
article well past the posting date there are probably newer versions -
poke around the repository to find out what the latest version is.)
Unpack the demo source jar to a temporary location, then copy the five
files mentioned above into the appropriate places in the hierarchy.
Download
scala,
log4j and
commons-fileupload (if you haven't already),
drop in a buld.xml
file (see below),
and modify the properties to fit your environment.
At that point you should be able to run a simple ant
command to create a war file in the build directory.
Copy that war file into the webapps directory, and you should
be able to see the demo page in the standard way from your web browser.
After that, you are on your own. Obviously this very simple setup does not handle dependencies like Maven does, so when those dependencies get updated, you will have to manually manage that process. And when you build up your code and start using other features, you will have to manually add additional jar files to
build.xml
.
But for some of us, that's just what we want.
The size of the
src
directory listed above is
under 60KB, the two liftweb jar files are under 3MB together, and the
scala and other two libraries are, combined, just over 4MB.
The war file weighs in at 6.3MB.
The original liftweb demo download includes some tests that I did not
include in my war file, so it could be that the tests use a few more
of those 82 jar files that Maven downloaded.
The build file below is pretty simple. There are really only two commands necessary to build the webapp: first compile the two scala files, then build the war file. I hope this post has made it clear that you don't need Maven at all to use Lift, and that Lift webapps are satisfactorily small and simple to build and run.
Ant Build File
Here is my samplebuid.xml
file
for building the Liftweb demo without Maven.
Remember to review the properties and change them as appropriate
for your environment.
In particular, you will almost certainly
want to change the home.dir
property, and probably the jar file locations as well.
If you create a lib
directory in your
liftdemo
directory and put the five
libraries there, you can simplify the build file by getting rid of
home.dir
and a number of the properties
used to define the locations of the libraries.
<project name="liftdemo" default="war"> <target name="init" description="Initialize all properties and paths"> <property name="home.dir" value="/u/jimmc"/> <property name="build.dir" value="build"/> <property name="class.dir" value="${build.dir}/class"/> <property name="scala.src.dir" value="src/scala"/> <property name="war.build.dir" value="${build.dir}/war"/> <property name="war.lib.dir" value="${war.build.dir}/WEB-INF/lib"/> <property name="war.file" value="build/liftdemo.war"/> <property name="web.xml" value="src/webapp/web.xml"/> <!-- Location of scala files --> <property name="scala.dir" value="${home.dir}/net/scala/scala-current"/> <property name="scala-compiler.jar" value="${scala.dir}/lib/scala-compiler.jar"/> <property name="scala-library.jar" value="${scala.dir}/lib/scala-library.jar"/> <!-- Location of Liftweb files --> <property name="liftweb.dir" value="${home.dir}/net/liftweb/1.0"/> <property name="lift-util.jar" value="${liftweb.dir}/lift-util-1.0.jar"/> <property name="lift-webkit.jar" value="${liftweb.dir}/lift-webkit-1.0.jar"/> <!-- A couple of other libraries are required --> <property name="log4j.jar" value="${home.dir}/net/log4j/log4j-1.2.14.jar"/> <property name="fileupload.jar" value="${home.dir}/net/fileupload/commons-fileupload-1.2.1.jar"/> <path id="scala.classpath"> <pathelement location="${scala-compiler.jar}"/> <pathelement location="${scala-library.jar}"/> </path> <path id="compile.classpath"> <path refid="scala.classpath"/> <pathelement location="${lift-util.jar}"/> <pathelement location="${lift-webkit.jar}"/> </path> <!-- define the "scalac" ant task --> <taskdef resource="scala/tools/ant/antlib.xml"> <classpath refid="scala.classpath"/> </taskdef> </target> <target name="clean" depends="init"> <delete dir="${build.dir}"/> </target> <target name="mkdirs" depends="init"> <mkdir dir="${build.dir}"/> <mkdir dir="${class.dir}"/> </target> <target name="compile" depends="init,mkdirs" description="Compile scala files"> <scalac srcdir="${scala.src.dir}" destdir="${class.dir}" addparams="-g:vars" classpathref="compile.classpath" force="changed" deprecation="on" > <include name="**/*.scala"/> </scalac> </target> <target name="war" depends="init,compile"> <!-- First make an image directory in war.build.dir --> <copy todir="${war.build.dir}"> <fileset dir="src/webapp" includes="**/*.html"/> </copy> <mkdir dir="${war.build.dir}/WEB-INF"/> <copy todir="${war.lib.dir}" file="${scala-library.jar}"/> <copy todir="${war.lib.dir}" file="${lift-util.jar}"/> <copy todir="${war.lib.dir}" file="${lift-webkit.jar}"/> <copy todir="${war.lib.dir}" file="${log4j.jar}"/> <copy todir="${war.lib.dir}" file="${fileupload.jar}"/> <copy todir="${war.build.dir}/WEB-INF/classes"> <fileset dir="${class.dir}" includes="**/*.class"/> </copy> <!-- Put everything from our war directory into a war file --> <war destfile="${war.file}" webxml="${web.xml}" > <fileset dir="${war.build.dir}" includes="**/*"/> </war> </target> </project>