Friday Sep 09, 2011

Scala and Maven - Getting Started Guide using maven-scala-plugin (TOTD #170)

Here is a quick Tip Of The Day (TOTD) that shows a "pom.xml" to get you started with building and running your Scala applications using Maven.

  1. Generate the Maven project
    D:\code\samples>mvn archetype:generate \
          -DarchetypeGroupId=org.scala-tools.archetypes \
          -DarchetypeArtifactId=scala-archetype-simple  \
          -DremoteRepositories=http://scala-tools.org/repo-releases \
          -DgroupId=org.glassfish.samples \
          -DartifactId=scala-helloworld \
          -Dversion=1.0-SNAPSHOT
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building Maven Stub Project (No POM) 1
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
    [INFO]
    [INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
    [INFO]
    [INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom ---
    [INFO] Generating project in Interactive mode
    [INFO] Archetype [org.scala-tools.archetypes:scala-archetype-simple:1.3] found in catalog remote
    [INFO] Using property: groupId = org.glassfish.samples
    [INFO] Using property: artifactId = scala-helloworld
    [INFO] Using property: version = 1.0-SNAPSHOT
    [INFO] Using property: package = org.glassfish.samples
    Confirm properties configuration:
    groupId: org.glassfish.samples
    artifactId: scala-helloworld
    version: 1.0-SNAPSHOT
    package: org.glassfish.samples
    Y: : Y
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 6.452s
    [INFO] Finished at: Fri Sep 09 09:59:53 PDT 2011
    [INFO] Final Memory: 12M/153M
    [INFO] ------------------------------------------------------------------------
    
    
    This command gets into an interactive mode confirming the entered details. After confirming, the generated directory structure looks like:

    .
    ./.gitignore
    ./pom.xml
    ./src
    ./src/main
    ./src/main/scala
    ./src/main/scala/org
    ./src/main/scala/org/glassfish
    ./src/main/scala/org/glassfish/samples
    ./src/main/scala/org/glassfish/samples/App.scala
    ./src/test
    ./src/test/scala
    ./src/test/scala/samples
    ./src/test/scala/samples/junit.scala
    ./src/test/scala/samples/scalatest.scala
    ./src/test/scala/samples/specs.scala
    And the generated "pom.xml" looks like:
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.glassfish.samples</groupId>
      <artifactId>scala-helloworld</artifactId>
      <version>1.0-SNAPSHOT</version>
      <name>${project.artifactId}</name>
      <description>My wonderfull scala app</description>
      <inceptionYear>2010</inceptionYear>
      <licenses>
        <license>
          <name>My License</name>
          <url>http://....</url>
          <distribution>repo</distribution>
        </license>
      </licenses>
    
      <properties>
        <maven.compiler.source>1.5</maven.compiler.source>
        <maven.compiler.target>1.5</maven.compiler.target>
        <encoding>UTF-8</encoding>
        <scala.version>2.8.0</scala.version>
      </properties>
    
      <!--
      <repositories>
        <repository>
          <id>scala-tools.org</id>
          <name>Scala-Tools Maven2 Repository</name>
          <url>http://scala-tools.org/repo-releases</url>
        </repository>
      </repositories>
    
      <pluginRepositories>
        <pluginRepository>
          <id>scala-tools.org</id>
          <name>Scala-Tools Maven2 Repository</name>
          <url>http://scala-tools.org/repo-releases</url>
        </pluginRepository>
      </pluginRepositories>
      -->
      <dependencies>
        <dependency>
          <groupId>org.scala-lang</groupId>
          <artifactId>scala-library</artifactId>
          <version>${scala.version}</version>
        </dependency>
    
        <!-- Test -->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.8.1</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.scala-tools.testing</groupId>
          <artifactId>specs_${scala.version}</artifactId>
          <version>1.6.5</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.scalatest</groupId>
          <artifactId>scalatest</artifactId>
          <version>1.2</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
          <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <version>2.15.0</version>
            <executions>
              <execution>
                <goals>
                  <goal>compile</goal>
                  <goal>testCompile</goal>
                </goals>
                <configuration>
                  <args>
                    <arg>-make:transitive</arg>
                    <arg>-dependencyfile</arg>
                    <arg>${project.build.directory}/.scala_dependencies</arg>
                  </args>
                </configuration>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.6</version>
            <configuration>
              <useFile>false</useFile>
              <disableXmlReport>true</disableXmlReport>
              <!-- If you have classpath issue like NoDefClassError,... -->
              <!-- useManifestOnlyJar>false</useManifestOnlyJar -->
              <includes>
                <include>**/*Test.*</include>
                <include>**/*Suite.*</include>
              </includes>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    
  2. Edit the "pom.xml" to specify a script to be launched. Add the following code fragment after </executions> for "maven-scala-plugin":
    <configuration>
      <launchers>
        <launcher>
          <id>sample</id>
          <mainClass>org.glassfish.samples.App</mainClass>
          <args>
            <arg>${basedir}</arg>
          </args>
        </launcher>
      </launchers>
    </configuration>
    
  3. Build and run the project as:

    D:\code\samples\scala-helloworld>mvn scala:run
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building scala-helloworld 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] >>> maven-scala-plugin:2.15.0:run (default-cli) @ scala-helloworld >>>
    [INFO]
    [INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ scala-helloworld ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] skip non existing resourceDirectory D:\code\samples\scala-helloworld\src\main\resources
    [INFO]
    [INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ scala-helloworld ---
    [INFO] Nothing to compile - all classes are up to date
    [INFO]
    [INFO] --- maven-scala-plugin:2.15.0:compile (default) @ scala-helloworld ---
    [INFO] Checking for multiple versions of scala
    [INFO] includes = [**/*.scala,**/*.java,]
    [INFO] excludes = []
    [INFO] D:\code\samples\scala-helloworld\src\main\scala:-1: info: compiling
    [INFO] Compiling 1 source files to D:\code\samples\scala-helloworld\target\classes at 1315588676077
    [INFO] No known dependencies. Compiling everything
    [INFO] prepare-compile in 0 s
    [INFO] compile in 5 s
    [INFO]
    [INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ scala-helloworld ---
    
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] skip non existing resourceDirectory D:\code\samples\scala-helloworld\src\test\resources
    [INFO]
    [INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ scala-helloworld ---
    [INFO] Nothing to compile - all classes are up to date
    [INFO]
    [INFO] --- maven-scala-plugin:2.15.0:testCompile (default) @ scala-helloworld ---
    [INFO] Checking for multiple versions of scala
    [INFO] includes = [**/*.scala,**/*.java,]
    [INFO] excludes = []
    [INFO] D:\code\samples\scala-helloworld\src\test\scala:-1: info: compiling
    [INFO] Compiling 3 source files to D:\code\samples\scala-helloworld\target\test-classes at 131558868
    1986
    [INFO] No known dependencies. Compiling everything
    [INFO] prepare-compile in 0 s
    [INFO] compile in 10 s
    [INFO]
    [INFO] <<< maven-scala-plugin:2.15.0:run (default-cli) @ scala-helloworld <<<
    [INFO]
    [INFO] --- maven-scala-plugin:2.15.0:run (default-cli) @ scala-helloworld ---
    [INFO] Checking for multiple versions of scala
    [INFO] launcher 'sample' selected => org.glassfish.samples.App
    Hello World!
    concat arguments = D:\code\samples\scala-helloworld
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 18.970s
    [INFO] Finished at: Fri Sep 09 10:18:13 PDT 2011
    [INFO] Final Memory: 10M/153M
    [INFO] ------------------------------------------------------------------------

    Look for the output "Hello World!" towards the bottom.

Fire away to add more classes and build your application. A subsequent blog will show how to perform database connectivity from a Scala application.

The generated project can be downloaded from totd170-scala-helloworld.zip.

More details at:

Wednesday Jun 16, 2010

Uber Conf 2010 - Notes from Scala for Java Programmers Workshop

I spent the first half of Day 3 of Uber Conf 2010 (Day 2 and 1) in Scala for Java Programmers workshop by Venkat, took extensive notes, and noted/tried pretty much all the code samples.

<warning>
This is a code intensive and slightly long entry.
</warning>

A more complete entry covering other events of Day 3 will come later today.

Lets go down the rabbit hole!

  • Why Scala ? - Scala is highly concise, expressive, nice support for XML processing, pattern matching, inherent support for authoring concurrent code - lot of good things to write efficient code.
  • Scala means SCAlable LAnguage - comes from the fact that you can write either a small script or a complete application using Scala.
  • An application developed on single core and deployed on multi-core can easily misbehave, primarily because of the concurrency model in Java. Scala makes it much easier to write concurrent applications (more on this below).
  • Writing correct synchronized code in Java requires divine power. Multi-threaded programming in Java is like working with mother-in-law, basically waiting for you to fail.
  • Scala complies with Java semantics without you worrying about it. "-savedcompile" saves the generated class files as JAR in the local directory.

Here is the first sample code that calculates the factorial of a number:

def fact(number: Int) = {
 var total = 1
 for (i <- 1 to number) {
     total = total \* i
 }
 total
}

println(fact(5))

Key points about this code (differences from Java):

  • Each class is "public" by default
  • No "main" method
  • "return" keyword is not required
  • The index "i" is assigned a type using inference, integer in this case
  • "var" defines a variable

This was done as a user exercise and so I wrote my first Scala code today ... yeee-haw!

  • Recursion is very expressive but expensive because of multiple stacks. Scala makes it run iterative and so less expensive
  • Scala supports tail recursion to a fairly decent extent, only one level of stack and so less expensive.

Here is a re-write of the above function using simple iterative recursion:

def total(number:Int) : Int = {
    if (number == 1)
       return 1
    number \* total (number - 1)
}

println(total(5))

And now this method converted to use tail recursion

def total(number: Int) : Int = {
   def totalWithAccumulator(accumulator: Int, number: Int) : Int = {
       if (number == 1) 
           accumulator
       else
           totalWithAccumulator(accumulator \* number, number - 1)
   }
   totalWithAccumulator(1, number)
}
println(total(5))

Here is a function that calculates the total of elements in a list:

def total(list: List[int]) = {
    var total = 0
    for (e <- list)
       total = total + e
    total
}

val list = List(1,2,4,5,6,3)
println(total(list))

This is using iterative approach - keep modifying the variable over & again and tells the next step. In functional, variables are constant and never changed. And here is a new method using the functional capabilities:


// imperative
def total(list: List[int]) = {
    var total = 0
    for (e <- list)
        total = total + e
    total
}

// functional
def total2(list: List[int]) = {
    list.foldLeft(0) {
       (carryOver, e) => carryOver + e
    }
}

val list = List(1,2,4,5,6,3)
println(total(list))
println(total2(list))

In Scala

a.+(b);

is equivalent to
a + b

".", parentheses, and ";" are optional.

When the method name ends with the colon, Scala will transpose them. The following code snippet shows this and some other features of the language:

val list = List(1,2,4,5,6,3)

// Imperative
var total1 = 0
for (e <- list)
    total1 = total1 + e
println("Total is " + total1)

// Functional
val total2 = list.foldLeft(0) { (carryOver, e) => carryOver + e }
println("Total is " + total2)

// Transposition using colon
// /: is a different name for foldLeft
var total3 = (0 /: list) { (carryOver, e) => carryOver + e }
println("Total is " + total3)

// No name required if the parameters are used only once
var total4 = (0 /: list) { _ + _ }
println("Total is " + total4)

// Pipe the method
def add(op1: Int, op2: Int) = { op1 + op2 }
val total5 = (0 /: list) { add }
println("Total is " + total5)
  • No primitive types in Scala, everything is an object

Code samples of closures in Scala ...

def totalSelectedNumbers(list:List[Int], selector: Int => boolean) = {
    var total = 0
    for (e <- list)
        if (selector(e)) total = total + e
    total
}


val list = List(1,2,4,5,6,3)
println(totalSelectedNumbers(list, { e => true }))
println(totalSelectedNumbers(list, { e => e % 2 == 0 }))
println(totalSelectedNumbers(list, { e => e > 4 }))
println(totalSelectedNumbers(list, { _ > 4 }))

Notice how "println" becomes more concise over subsequent lines. And a further cleaner, and concise, version can be written by allowing multiple lists to be passed to the function as shown below:

// Multiple lists to the function
def totalSelectedNumbers(list:List[Int]) (selector: Int => boolean) = {
    var total = 0
    for (e <- list)
       if (selector(e)) total = total + e
    total
}

val list = List(1,2,4,5,6,3)
println(totalSelectedNumbers(list) { _ > 4 })

Here is another exercise to write a function that doubles the number in the list:

val list = List(1,2,4,5,6,3)
println(list.map { _ \* 2 })

And another exercise to find the maximum number of a list

val list = List(1,2,4,5,6,3,2,7)
val max = (list(0) /: list) { (max, e) =>
             if (e > max) e else max
          }
println (max)


And then a simplified method definition ...

println((list(0) /: list) { Math.max })

  • In Scala: "val" creates a pointer that cannot change, "var" creates a pointer that can change but the objects are immutable.
  • In Scala, everything is public unless you say otherwise.
  • Code within the class runs within the primary constructor. In Scala, there is only one constructor, every other is called as auxiliary constructor and they always go through the primary constructor. Only primary constructor can call super (only path to the base class)

Here is a simple class definition:

class Car(val year: int, var miles: Int) {

    // invokes with primary constructor
    println("hello there")

    // year has a getter, miles has a getter/setter
    def drive(dist: Int) = {
       miles += dist
    }

    // private method only to this instance
    private[this] def tuneup {}
}

val car = new Car(2010, 0)
println(car.year)
println(car.miles)
car drive 10
println(car.miles)
  • Scala is a purely OO language, new methods can be defined easily on any object

Here is a sample code that demonstrates adding a new method:

import java.util._ // static import

class IntUtil(number: Int) {
   def days = this
   def ago = {
      var cal = Calendar.getInstance()
      cal.add(Calendar.DAY_OF_MONTH, -number)
      cal.getTime()
   }
}

val num = 2
val obj = new IntUtil(num)
println(obj.days.ago)
  • Scala has no primitive types, everything is an object.
  • New methods can be easily added using "implicit conversion"

Here is a code sample that shows how to perform "implicit conversion" and add a new method to a "val"

import java.util._ // static import

class IntUtil(number: Int) {
   def days = this
   def ago = {
      var cal = Calendar.getInstance()
      cal.add(Calendar.DAY_OF_MONTH, -number)
      cal.getTime()
   }
}

val num = 2
val obj = new IntUtil(num)
println(obj.days.ago)

// implicit conversion - only one conversion can be applied per object (or class??)
implicit def pleaseConvertInt2WonderfulIntUtil(number: Int) = new IntUtil(number)

println(2.days.ago)
  • To create Singleton, use the word "object" such as:
class Car {
}

object Car {
    // place all the static methods here
}
  • This singleton object is also called the "companion" object and it must exist in the same file as the original object.
  • Companion object is used to create the factory pattern.
  • Adding "private" to the class definition makes the constructor private.
  • "apply" is a special method: "blah.apply(something)" is equivalent to "blah(something)"
  • "apply" has a cousin "update" and takes 2 parameters

Here is a code that demonstrates some of the above mentioned features:

import scala.collection.mutable._

class Pen private (val color: String) {
    println(color + " pen being created")
}

// companion object - singleton
object Pen {
    val pens : Map[String, Pen] = Map()
    def createPen(color: String) = {
        if (!pens.contains(color))
            pens(color) = new Pen(color)
            // == pens.update(color, new Pen(color)
        pens.get(color)
    }
}

val bluePen = Pen.createPen("blue")
val bluePen2 = Pen.createPen("blue")
val redPen = Pen.createPen("red")

Running this code shows that "blue" pen is created only once and cached during second attempt. Notice, how the Pen is created using "createPen" factory method. This code can be changed to use "apply" as:

import scala.collection.mutable._

class Pen private (val color: String) {
    println(color + " pen being created")
}

// companion object - singleton
object Pen {
    val pens : Map[String, Pen] = Map()
    def apply(color: String) = {
        if (!pens.contains(color))
            pens(color) = new Pen(color)
        pens.get(color)
    }
}

val bluePen = Pen("blue")
val bluePen2 = Pen("blue")
val redPen = Pen("red")

Notice how default constructors instead of the factory pattern are now used.

Here is a piece of code that has two classes with similar functionality:

class Human(val name: String) {
 def listen = println("I am " + name + " your friend")
}

class Animal(val name: String)

class Dog(override val name: String) extends Animal(name) {
 def listen = println("I am " + name + " your friend")
}

val peter = new Human("Peter")
peter.listen

val rover = new Dog("Rover")
rover.listen

This violates the DRY principle. Scala Traits allows to encapsulate the code as shown below:

trait Friend {
 val name: String
 def listen = println("I am " + name + " your friend")
}

class Human(val name: String) extends Friend

class Animal(val name: String)

class Dog(override val name: String) extends Animal(name) with Friend

val peter = new Human("Peter")
peter.listen

val rover = new Dog("Rover")
rover.listen


// include trait at an object level
class Cat(override val name: String) extends Animal(name)

val molly = new Cat("Molly") with Friend
molly.listen
  • XML processing is a first class citizen in Scala
val xml = therethere
println(xml)

// XPath query
println(xml \\\\ "@greet")
println(xml \\\\ "where")
val stock = Map("APPL" -> 250, "GOOG" -> 300)

def createStock() = {
 stock.map { entry =>  }
}

// Scala code within XML
val xml = { createStock() }

println(xml)

Here is the last exercise from the workshop: Use Yahoo Weather API to find the temperature of Denver, CO:

import scala.xml._
import scala.io._
import java.net._

val theURL = "http://weather.yahooapis.com/forecastrss?w=2391279&u=f"

val xmlString = Source.fromURL(new URL(theURL)).mkString
//println(xmlString)    // for debugging

val xml = XML.loadString(xmlString)

val city = xml \\\\ "location" \\\\ "@city"
val state = xml \\\\ "location" \\\\ "@region"
val temperature = xml \\\\ "condition" \\\\ "@temp"

println("Temperature in " + city + ", " + state + " is " + temperature)
  • Actors enable concurrency in Scala, "receive" is used to receive the response from each Actor
  • Don't use "receive" outside, use receive within
  • OK to share Java code within Scala only if its mutable
  • Scala has "tuples", are immutables, and really good candidate for concurrency

Here is a sample code refactoring the above code in a method, called 50 times in a loop, printed once using traditional method invocation and once using Actors. The total time taken for the two set of executions is then printed.

import scala.xml._
import scala.io._
import java.net._
import scala.actors._
import Actor._

def getTemperature(woeid: Int) = {

    val theURL = "http://weather.yahooapis.com/forecastrss?w=" + woeid + "&u=f"

    val xmlString = Source.fromURL(new URL(theURL)).mkString
    val xml = XML.loadString(xmlString)

    val city = xml \\\\ "location" \\\\ "@city"
    val state = xml \\\\ "location" \\\\ "@region"
    val temperature = xml \\\\ "condition" \\\\ "@temp"

    (city, state, temperature)      // tuples are immutable
                                    // good candidates for concurrency
}

val start = System.nanoTime
for (woeid <- 2391250 to 2391299) {
    println(getTemperature(woeid))
}
val end = System.nanoTime
println("Time taken (without Actor): " + (end - start)/100000000.0) 

// Now dispatching to multiple actors
val start2 = System.nanoTime
val caller = self               // self is a pointer to my actor
for (woeid <- 2391250 to 2391299) {
    actor { caller ! getTemperature(woeid) }      // Dispatch 50 actors
}

for (woeid <- 2391250 to 2391299) {
    receive {
       case msg => println(msg)
    }
}
val end2 = System.nanoTime

println("Time taken (with Actor): " + (end2 - start2)/100000000.0)

A sample result from running this script showed the results:

Time taken (without Actor): 171.62816
Time taken (with Actor): 29.05179

As you can see the difference is quite evident - approx 6x better performance when using Actors.

Overall, super excited after writing so much Scala code and learned something new.

Thank you Venkat for yet another great workshop!

Technorati: conf uberconf scala java workshop

Friday Sep 04, 2009

TOTD #101: Applying Servlet 3.0/Java EE 6 “web-fragment.xml” to Lift – Deploy on GlassFish v3

TOTD #100 explained how to deploy Lift framework applications on GlassFish v3. As explained in TOTD #91, Java EE 6 defines how the framework configuration deployment descriptor can be defined in “META-INF/web-fragment.xml” in the JAR file of the framework instead of mixing it with "WEB-INF/web.xml" which is intended for application deployment descriptor aspects.

This Tip Of The Day (TOTD) explains how to leverage ”web-fragment.xml” to deploy a Lift application on a Java EE 6 compliant container. The original "lift-\*.jar" files are untouched and instead a new JAR file is included that contains only the framework configuration deployment descriptor.

The generated "web.xml" from TOTD #100 looks like:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<filter>
 <filter-name>LiftFilter</filter-name>
 <display-name>Lift Filter</display-name>
 <description>The Filter that intercepts lift calls</description>
 <filter-class>net.liftweb.http.LiftFilter</filter-class>
</filter>
 

<filter-mapping>
 <filter-name>LiftFilter</filter-name>
 <url-pattern>/\*</url-pattern>
</filter-mapping>

</web-app>

The deployment descriptor defines a Servlet Filter (LiftFilter) that registers the Lift framework with the Web container. And then it defines a URL mapping to "/\*". All of this information is required by the Lift framework for request dispatching. And so that makes this fragment suitable for "web-fragment.xml".

Here are simple steps to make this change:

  1. Remove “src/main/webapp/WEB-INF/web.xml” because no application specific deployment descriptors are required.
  2. Include “lift-web-fragment.jar” in the “WEB-INF/lib” of your application by adding the following fragment in your “pom.xml”:
    <dependencies>
            
    . . .
    
      <!– web-fragment –>
      <dependency>
        <groupId>org.glassfish.extras</groupId>
        <artifactId>lift-web-fragment</artifactId>
        <version>1.0</version>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
    
    . . .
    
    <repositories>
      <repository>
        <id>maven2-repository.dev.java.net</id>
        <name>Java.net Repository for Maven</name>
        <url>http://download.java.net/maven/2/</url>
      </repository>
    </repositories>
    
    
    This file contains only “META-INF/web-fragment.xml” with the following content:
    <web-fragment>
     <filter>
     <filter-name>LiftFilter</filter-name>
     <display-name>Lift Filter</display-name>
     <description>The Filter that intercepts lift calls</description>
     <filter-class>net.liftweb.http.LiftFilter</filter-class>
     </filter>
     
    
     <filter-mapping>
     <filter-name>LiftFilter</filter-name>
     <url-pattern>/\*</url-pattern>
     </filter-mapping>
    </web-fragment>
    
    
  3. Create the WAR file without “web.xml” by editing “pom.xml” and adding the following fragment:
    <build>
       . . .
      <plugins>
        . . .
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-war-plugin</artifactId>
          <version>2.1-beta-1</version>
          <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
          </configuration>
        </plugin>
      </plugins>
    </build>
    

That's it, now now you can create a WAR file using “mvn package” and deploy this web application on GlassFish v3 latest promoted build (61 as of today) as explained in TOTD #100.

Technorati: totd glassfish v3 lift scala javaee6 servlet web-fragment

Thursday Sep 03, 2009

TOTD #100: Getting Started with Scala Lift on GlassFish v3

Yaaay, 100th tip! Read earlier tips here.
Scala is a strongly typed JVM language that provides benefits of functional programming and dynamic languages on the JVM. As a result you get flexibility of language such as Ruby and performance of Java. Lift is an MVC-based Web framework, based on Scala, that claims to pick the best of Rails (ease of development), Seaside (highly granular sessions and security), Django (access control), and Wicket (designer-friendly templating system).

Lift applications can run inside any Java application server. GlassFish v3 can run Rails and Django applications natively and can also run Wicket applications. This Tip Of The Day (TOTD) explains how to get started with Lift applications and run inside GlassFish v3.

  1. Create a new Lift project using Maven as shown:

    ~/samples/v3/lift >mvn archetype:generate -U -DarchetypeGroupId=net.liftweb 
    -DarchetypeArtifactId=lift-archetype-blank -DarchetypeVersion=1.0 
    -DremoteRepositories=http://scala-tools.org/repo-releases 
    -DgroupId=demo.helloworld -DartifactId=helloworld 
    -Dversion=1.0-SNAPSHOT
     [INFO] Scanning for projects...
     [INFO] Searching repository for plugin with prefix: 'archetype'.
     [INFO] org.apache.maven.plugins: checking for updates from central
    
     . . .
    
     [INFO] ------------------------------------------------------------------------
     [INFO] BUILD SUCCESSFUL
     [INFO] ------------------------------------------------------------------------
     [INFO] Total time: 14 seconds
     [INFO] Finished at: Tue Sep 01 16:11:34 PDT 2009
     [INFO] Final Memory: 12M/80M
     [INFO] ------------------------------------------------------------------------
    


    This creates a directory "helloworld" which looks like:

    ~/samples/v3/lift/helloworld >find .
    .
    ./pom.xml
    ./src
    ./src/main
    ./src/main/resources
    ./src/main/scala
    ./src/main/scala/bootstrap
    ./src/main/scala/bootstrap/liftweb
    ./src/main/scala/bootstrap/liftweb/Boot.scala
    ./src/main/scala/demo
    ./src/main/scala/demo/helloworld
    ./src/main/scala/demo/helloworld/comet
    ./src/main/scala/demo/helloworld/comet/.keep
    ./src/main/scala/demo/helloworld/model
    ./src/main/scala/demo/helloworld/model/.keep
    ./src/main/scala/demo/helloworld/snippet
    ./src/main/scala/demo/helloworld/snippet/.keep 
    ./src/main/scala/demo/helloworld/snippet/HelloWorld.scala
    ./src/main/scala/demo/helloworld/view
    ./src/main/scala/demo/helloworld/view/.keep
    ./src/main/webapp
    ./src/main/webapp/index.html
    ./src/main/webapp/templates-hidden
    ./src/main/webapp/templates-hidden/default.html
    ./src/main/webapp/WEB-INF
    ./src/main/webapp/WEB-INF/web.xml
    ./src/test
    ./src/test/resources
    ./src/test/scala
    ./src/test/scala/demo
    ./src/test/scala/demo/helloworld
    ./src/test/scala/demo/helloworld/AppTest.scala
    ./src/test/scala/LiftConsole.scala
    ./src/test/scala/RunWebApp.scala
    


    In this directory, "src/main/scala" contains Scala source code, "src/main/webapp" contains the HTML and other related artifacts, and "src/test/scala" contains a simple test case to test the generated application. The "demo/helloworld/model" directory is used for models, "demo/helloworld/snippet" for controller, and "demo/helloworld/view" for views. The Lift Getting Started Guide provides a detailed explanation of how the different components work together to provide the end result.
  2. Create a WAR file of the application as:
    ~/samples/v3/lift/helloworld >mvn package [INFO] Scanning for projects...
     [INFO] ------------------------------------------------------------------------
     [INFO] Building helloworld
     [INFO] task-segment: [package]
     [INFO] ------------------------------------------------------------------------
     [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] Building war: /Users/arungupta/samples/v3/lift/helloworld/target/helloworld-1.0-SNAPSHOT.war
     [INFO] ------------------------------------------------------------------------
     [INFO] BUILD SUCCESSFUL
     [INFO] ------------------------------------------------------------------------
     [INFO] Total time: 9 minutes 25 seconds
     [INFO] Finished at: Tue Sep 01 16:42:32 PDT 2009
     [INFO] Final Memory: 24M/80M
     [INFO] ------------------------------------------------------------------------
    


    This generates "target/helloworld-1.0-SNAPSHOT.war" file.
  3. The WAR file can be easily deployed to GlassFish v3. Download the latest GlassFish v3 promoted build (61 as of this writing) and unzip. Start the GlassFish server as:
    ~/tools/glassfish/v3/61/glassfishv3 >./bin/asadmin start-domain --verbose
    
    Sep 2, 2009 3:43:09 PM com.sun.enterprise.admin.launcher.GFLauncherLogger info
    INFO: JVM invocation command line:
    
    . . .
    
    Sep 2, 2009 3:46:01 PM OSGiModuleImpl start
    INFO: Started bundle org.glassfish.security [174]
    Sep 2, 2009 3:46:02 PM OSGiModuleImpl start
    INFO: Started bundle org.glassfish.deployment.javaee-full [51]
    

    and deploy the WAR file as:
    ~/samples/v3/lift/helloworld >~/tools/glassfish/v3/8-31/glassfishv3/bin/asadmin deploy target/helloworld-1.0-SNAPSHOT.war
    
    Command deploy executed successfully.
    


    The app is now accessible at "http://localhost:8080/helloworld-1.0-SNAPSHOT/" and the output looks like:

What application server are you using to deploy your Lift applications ?

Please leave suggestions on other TOTD that you’d like to see. A complete archive of all the tips is available here.

Technorati: totd scala lift glassfish v3

About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today