Monday, August 16, 2010

Lift, Scala, Maven on Google App engine

Now that Lift 2.0 and Scala 2.8 has been released, it might be a good time to play around and see how useful these technologies might be. I've also wanted to try out GAE and I've incorporated that in this example.

Here are some basic steps to get you started ..

  • I use eclipse, so the following couple of steps are eclipse related.
  • Install the google app engine plugin into eclipse
  • Install Scala IDE in eclipse
  • If you dont have maven installed locally, install maven


Now lets create a simple lift prototype project.

  • Use the following command to create your maven project. 
  • mvn archetype:generate -U -DarchetypeGroupId=net.liftweb -DarchetypeArtifactId=lift-archetype-basic -DarchetypeVersion=2.0-scala280-SNAPSHOT
        -DarchetypeRepository=
    http://scala-tools.org/repo-snapshots 
        -DremoteRepositories=
    http://scala-tools.org/repo-snapshots
     -DgroupId=com.ak.fun -DartifactId=stuff
  • The groupId will signify your package structure and the artifactId will be your project name, so rename them accordingly
  • Open up eclipse. If you dont have m2eclipse/m2eclipse-scala installed, install it according to the instructions
  • Import the project you created into Eclipse. Open the Scala view, right click on your project and insert Scala Nature
  • Enable Maven dependency (right click -> m2 -> enable dependency)
  • Your project should now compile fine and you should be able to see the start up page if you run mvn:jetty and go to http://localhost:8080/
Add google appengine settings: 

GAE doesnt play well with maven out of the box, so we need to make some changes. Lets add some classpath entries.

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
        <classpathentry kind="src" path="src/main/scala"/>
        <classpathentry excluding="**" kind="src" path="src/main/resources"/>
        <classpathentry kind="src" output="war" path="src/main/webapp"/>
        <classpathentry kind="src" output="target/test-classes" path="src/test/scala"/>
        <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
        <classpathentry kind="con" path="ch.epfl.lamp.sdt.launching.SCALA_CONTAINER"/>
        <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
        <classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
        <classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath>

GAE likes deploying off the 'war' directory, so we compile our classes to that directory. We also need to add the library files as GAE does not recognize any of the pom.xml entries. The easiest way to do it, is modify pom.xml to copy dependencies to the lib directory.

  <build>
    <sourceDirectory>src/main/scala</sourceDirectory>
    <testSourceDirectory>src/test/scala</testSourceDirectory>
    <outputDirectory>war/WEB-INF/classes</outputDirectory>
                <plugins>
                        <plugin>
                            <artifactId>maven-clean-plugin</artifactId>
                            <version>2.4.1</version>
                            <configuration>
                              <filesets>
                                <fileset>
                                  <directory>war/WEB-INF/lib</directory>
                                  <followSymlinks>false</followSymlinks>
                                </fileset>
                              </filesets>
                            </configuration>
                          </plugin>
              <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                    <executions>
                        <execution>
                            <phase>install</phase>
                            <goals>
                                <goal>copy-dependencies</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>war/WEB-INF/lib</outputDirectory>
                            </configuration>
                        </execution>
                    </executions>
              </plugin>

                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <version>2.0.2</version>
                                <configuration>
                                        <source>${maven.compiler.source}</source>
                                        <target>${maven.compiler.target}</target>
                                </configuration>
                        </plugin>
                        <plugin>
                                <artifactId>maven-war-plugin</artifactId>
                                <version>2.1-beta-1</version>
                                <configuration>
                                        <warSourceDirectory>war</warSourceDirectory>
                                </configuration>
                        </plugin>

You can set the maven.compiler.source/target to a particular version if you want to skip between 1.5/1.6

When you run mvn:install you should see the dependencies copied over to the lib directory.

The final step is adding the appengine-web.xml to the src/main/webapp/WEB-INF/ directory
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>id</application>
  <version>1</version>
  <system-properties> 
    <property name="in.gae.j" value="true" /> 
  </system-properties> 
  <sessions-enabled>true</sessions-enabled> 
  <static-files> 
    <exclude path="/**" /> 
  </static-files> 
</appengine-web-app>

Your application is now GAE ready.

p.s. I've noticed that if there are a few compile errors in Eclipse, the Scala-IDE freaks out and flags almost every line as an error (atleast in mine). The easiest way to fix it is clean-build the entire project (yes, I know its a little annoying)

1 comment:

David Bernard said...

Hi,

If you "Import the project as existing maven project". Then you should not need to
* add scala nature (done by m2eclipse-scala)
* enable Maven dependency (done by m2eclipse)

thanks for using our scala tools