Scala - Getting Started - Part 2
- 14 minutes read - 2771 wordsIn previous article we learned basics of Scala, in this articles we will learn how to setup build scripts for scala and build applications using scala.
We will also learn few web development frameworks for Scala and compare them with similar framework in Java.
Building Scala Applications
Below program demonstrates the use of Scala script with Maven, Ant, and logging library – LogBack.
Integration with Ant
Below example shows how Scala project can be built by the ant build.
- Scala build task
- Use of
ScalaTestAntTask
to run scala test case Antbuild.xml
<?xml version="1.0"?>
<project name="scalaantproject" default="run">
<!-- root directory of this project -->
<property name="project.dir" value="." />
<!-- main class to run -->
<property name="main.class" value="<full qualified main class name>" />
<!-- location of scalatest.jar for unit testing -->
<property name="scalatest.jar" value="${basedir}/lib/scalatest_2.9.0-1.9.1.ja”/>
<target name="init">
<property environment="env" />
<!-- derived path names -->
<property name="build.dir" value="${project.dir}/build" />
<property name="source.dir" value="${project.dir}/src" />
<property name="test.dir" value="${project.dir}/test" />
<!-- scala libraries for classpath definitions -->
<property name="scala-library.jar" value="${scala.home}/lib/scala-library.jar" />
<property name="scala-compiler.jar" value="${scala.home}/lib/scala-compiler.jar" />
<!-- classpath for the compiler task definition -->
<path id="scala.classpath">
<pathelement location="${scala-compiler.jar}" />
<pathelement location="${scala-library.jar}" />
</path>
<!-- classpath for project build -->
<path id="build.classpath">
<pathelement location="${scala-library.jar}" />
<fileset dir="${project.dir}/lib">
<include name="*.jar" />
</fileset>
<pathelement location="${build.dir}/classes" />
</path>
<!-- classpath for unit test build -->
<path id="test.classpath">
<pathelement location="${scala-library.jar}" />
<pathelement location="${scalatest.jar}" />
<pathelement location="${build.dir}/classes" />
</path>
<!-- definition for the "scalac" and "scaladoc" ant tasks -->
<taskdef resource="scala/tools/ant/antlib.xml">
<classpath refid="scala.classpath" />
</taskdef>
<!-- definition for the "scalatest" ant task -->
<taskdef name="scalatest" classname="org.scalatest.tools.ScalaTestAntTask">
<classpath refid="test.classpath"/>
</taskdef>
</target>
<!-- delete compiled files -->
<target name="clean" depends="init" description="clean">
<delete dir="${build.dir}" />
<delete dir="${project.dir}/doc" />
<delete file="${project.dir}/lib/scala-library.jar" />
</target>
<!-- compile project -->
<target name="build" depends="init" description="build">
<buildnumber />
<tstamp />
<mkdir dir="${build.dir}/classes" />
<scalac srcdir="${source.dir}" destdir="${build.dir}/classes" classpathref="build.classpath" force="never" deprecation="on">
<include name="**/*.scala" />
</scalac>
</target>
<!-- run program -->
<target name="run" depends="build" description="run">
<java classname="${main.class}" classpathref="build.classpath" />
</target>
<!-- build unit tests -->
<target name="buildtest" depends="build">
<mkdir dir="${build.dir}/test" />
<scalac srcdir="${test.dir}" destdir="${build.dir}/test" classpathref="test.classpath" force="never" deprecation="on">
<include name="**/*.scala" />
</scalac>
</target>
<!-- run unit tests -->
<target name="test" depends="buildtest" description="test">
<scalatest runpath="${build.dir}/test">
<reporter type="stdout" config="FWD"/>
<reporter type="file" filename="${build.dir}/TestOutput.out" />
<membersonly package="suite" />
</scalatest>
</target>
<!-- create a startable *.jar with proper classpath dependency definition -->
<target name="jar" depends="build" description="jar">
<mkdir dir="${build.dir}/jar" />
<copy file="${scala-library.jar}" todir="${project.dir}/lib" />
<path id="jar.class.path">
<fileset dir="${project.dir}">
<include name="lib/**/*.jar" />
</fileset>
</path>
<pathconvert property="jar.classpath" pathsep=" " dirsep="/">
<path refid="jar.class.path">
</path>
<map from="${basedir}${file.separator}lib" to="lib" />
</pathconvert>
<jar destfile="${build.dir}/jar/${ant.project.name}.jar" basedir="${build.dir}/classes" duplicate="preserve">
<manifest>
<attribute name="Main-Class" value="${main.class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
<section name="Program">
<attribute name="Title" value="${ant.project.name}" />
<attribute name="Build" value="${build.number}" />
<attribute name="Date" value="${TODAY}" />
</section>
</manifest>
</jar>
</target>
<!-- create API documentation in doc folder -->
<target name="scaladoc" depends="build" description="scaladoc">
<mkdir dir="${project.dir}/doc" />
<scaladoc srcdir="${source.dir}" destdir="${project.dir}/doc" classpathref="build.classpath" doctitle="${ant.project.name}" windowtitle="${ant.project.name}" />
</target>
<!-- create a zip file with binaries for distribution -->
<target name="package" depends="jar, scaladoc" description="package">
<zip destfile="${build.dir}/${ant.project.name}.zip">
<zipfileset dir="${build.dir}/jar" includes="${ant.project.name}.jar" />
<zipfileset dir="${project.dir}" includes="lib/*" />
<zipfileset dir="${project.dir}" includes="doc/*" />
<zipfileset dir="${project.dir}/txt" includes="*" />
</zip>
</target>
</project>
Integration with Maven
Scale maven project can simply be created using ‘org.scala-tools.archetypes
’ archetypes. Example show pom.xml
file to build basic scala maven project
For maven to compile and understand the Scala class files, we should follow the following folder structure
project/
pom.xml - Defines the project
src/
main/
java/ - Contains all java code that will go in your final artifact.
scala/ - Contains all scala code that will go in your final artifact.
resources/ - Contains all static files that should be available on the classpath
in the final artifact.
webapp/ - Contains all content for a web application (jsps,css,images, etc.)
test/
java/ - Contains all java code used for testing.
scala/ - Contains all scala code used for testing.
resources/ - Contains all static content that should be available on the classpath during testing.
pom.xml
<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>com.tk.scala</groupId>
<artifactId>scalamavenpoc</artifactId>
<version>1.0</version>
<name>${project.artifactId}</name>
<description>scala maven poc application</description>
<inceptionYear>2010</inceptionYear>
<properties>
<encoding>UTF-8</encoding>
<scala.version>2.9.1</scala.version>
</properties>
<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_2.9.1</artifactId>
<version>1.6.9</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.2</version>
</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>
<includes>
<include>**/*Test.*</include>
<include>**/*Suite.*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Building Scala Web Application
This POC shows a simple web servlet using scala.
Scala web servlet example
Creating a web project that compiles your Scala code requires a little tweaking.
-
First, you should create a simple Dynamic Web Project. Then, open the
.project
file. -
Replace the
org.eclipse.jdt.core.javabuilder
withorg.scala-ide.sdt.core.scalabuilder
. -
Now add the Scala nature to your project:
<nature>org.scala-ide.sdt.core.scalanature</nature>.
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ScalaWebApplication</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.scala-ide.sdt.core.scalabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.scala-ide.sdt.core.scalanature</nature>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>
- If you made the right change, you should see a S instead of a J on your project’s icon.
- The last thing to do should be to add the Scala library to your path. Depending on your application server configuration, either add the Scala library to your build path (Build Path -> Configure Build Path -> Add Library -> Scala Library) or manually add the needed library to your
WEB-INF/lib
folder.
Web Servlet Program
package com.tk.servlet.scala
import javax.servlet.http.{ HttpServlet, HttpServletRequest, HttpServletResponse }
class ScalaServlet extends HttpServlet {
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) = {
resp.getWriter().print("<HTML>" +
"<HEAD><TITLE>Hello, Scala!</TITLE></HEAD>" +
"<BODY>Hello, Scala! This is a servlet.</BODY>" +
"</HTML>")
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
override def doPost(req: HttpServletRequest, resp: HttpServletResponse) = {
}
}
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ScalaWebApplication</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>helloWorld</servlet-name>
<servlet-class>com.tk.servlet.scala.ScalaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloWorld</servlet-name>
<url-pattern>/sayHello</url-pattern>
</servlet-mapping>
</web-app>
Scala web framework - Lift
Lift is a free web application framework that is designed for the Scala programming language. As Scala program code executes within the Java virtual machine (JVM), any existing Java library and web container can be used in running Lift applications. Lift web applications are thus packaged as WAR files and deployed on any servlet 2.4 engine (for example, Tomcat 5.5.xx, Jetty 6.0, etc.). Lift programmers may use the standard Scala/Java development toolchain including IDEs such as Eclipse, NetBeans and IDEA. Dynamic web content is authored via templates using standard HTML5 or XHTML editors. Lift applications also benefit from native support for advanced web development techniques such as Comet and Ajax. Lift does not prescribe the model–view–controller (MVC) architectural pattern. Rather Lift is chiefly modeled upon the so-called “View First” (designer friendly) approach to web page development inspired by the Wicket framework.
Lift Hello world application
Follow below steps to create simple lift web project
-
Create maven project with archetype ‘lift-archetype-blank_{version}’
-
Enter GroupId, ArtifactId, version, package just like normal maven project
-
This will create project structure with scala, lift and logback configured in it.
-
Project Structure Details
src/main - your application source src/main/webapp - contains files to be copied directly into your web application, such as html templates and the web.xml src/test - your test code target - where your compiled application will be created and packaged Boot.scala - defines the global setup for the application. The main things it does are: Defines the packages for Lift code Creates the sitemap – a menu and security access for the site Commet - Comet describes a model where the client sends an asynchronous request to the server. The request is hanging till the server has something interesting to respond. As soon as the server responds another request is made. The idea is to give the impression that the server is notifying the client of changes on the server. For more details refer: Wikipedia article. Snippet - in general is a programming term for a small region of re-usable source code, machine code, or text. Lift uses snippets to transform sections of the HTML page from static to dynamic. The key word is transform. Lift’s snippets are Scala functions: NodeSeq => NodeSeq. A NodeSeq is a collection of XML nodes. A snippet can only transform input NodeSeq to output NodeSeq.
-
Default generated code Explanation - Here is the servlet filter that runs a lift app
<?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>
-
Default Hello world snippet -
HelloWorld.scala
package com.tk.lift.poc { /** * declaring package for snippet classes */ package snippet { import _root_.scala.xml.NodeSeq import _root_.net.liftweb.util.Helpers import Helpers._ /** * Defining snippet class HelloWorld */ class HelloWorld { /** * defining snippet with name 'howdy' */ def howdy(in: NodeSeq): NodeSeq = /** * This snippet will replace '<b:time/> in html file * with current date string' */ Helpers.bind("b", in, "time" -> (new _root_.java.util.Date).toString) } } }
-
Default html page -
index.html
<lift:surround with="default" at="content"> <h2>Welcome to your project!</h2> <p> <lift:helloWorld.howdy> <span>Welcome to liftblank at <b:time/></span> </lift:helloWorld.howdy> </p> </lift:surround>
-
Default
Boot.scala
package bootstrap.liftweb
import _root_.net.liftweb.common._
import _root_.net.liftweb.util._
import _root_.net.liftweb.http._
import _root_.net.liftweb.sitemap._
import _root_.net.liftweb.sitemap.Loc._
import Helpers._
/**
* A class that's instantiated early and run. It allows the application
* to modify lift's environment
*/
class Boot {
def boot {
// where to search snippet
LiftRules.addToPackages("com.nagarro.lift.poc")
// This piece of code build SiteMap on thie index.html page
// we will see listing with 'home' attribute there
val entries = Menu(Loc("Home", List("index"), "Home")) :: Nil
LiftRules.setSiteMap(SiteMap(entries: _*))
}
}
- Running default web application
To run this webapp
- Build the project with maven clean install goal
- This will generate war file in target folder
- Deploy the war file in any servers like tomcat etc
Scala/Lift vs Java/Spring
Let’s assume we’re equally comfortable in Scala and Java, and ignore the (huge) language differences except as they pertain to Spring or Lift.(Probably a big assumption for java refuges)
Spring and Lift are almost diametrically opposed in terms of maturity and goals.
- Spring is about five years older than Lift
- Lift is monolithic and targets only the web; Spring is modular and targets both web and “regular” apps
- Spring supports a plethora of Java EE features; Lift ignores that stuff
Scala MVC framework - Play
Play is an open source web application framework, written in Scala and Java, which follows the model–view–controller (MVC)architectural pattern. It aims to optimize developer productivity by using convention over configuration, hot code reloading and display of errors in the browser. Support for the Scala programming language has been available since version 1.1 of the framework. In version 2.0, the framework core was rewritten in Scala. Build and deployment was migrated to Simple Build Tool and templates use Scala instead of Groovy.
Play - Hello World
- Install play framework
- Create new hello world application open command prompt and type following commands
play new helloworld –with scala
- It will prompt you for the application full name. Type Hello world.
- The play new command creates a new directory
helloworld/
and populates it with a series of files and directories, the most important being:
Play Project Structure
app/ contains the application’s core. It contains all the application *.scala files. You see that the default is a single controllers.scala file. You can of course use more files and organize them in several folders for more complex applications. Also the app/viewsdirectory is where template files live. A template file is generally a simple text, xml or html file with dynamic placeholders.
conf/ contains all the application’s configuration files, especially the main application.conf file, the routes definition files and the messages files used for internationalization.
lib/ contains all optional Scala libraries packaged as standard .jar files.
public/ contains all the publicly available resources, which includes JavaScript, stylesheets and images directories.
test/ contains all the application tests. Tests are either written either as ScalaTest tests or as Selenium tests.
As a Scala developer, you may wonder where all the .class
files go. The answer is nowhere: Play doesn’t use any class files but reads the Scala source files directly.
-
The main entry point of your application is the
conf/routes
file. This file defines all of the application’s accessible URLs. If you open the generated routes file you will see this first ‘route’:GET / Application.index
That simply tells Play that when the web server receives a
GET
request for the/
path, it must call theApplication.index
Scala method. In this case, Application.index is a shortcut forcontrollers.Application.index
, because the controller’s package is implicit. -
A Play application has several entry points, one for each URL. We call these methodsaction methods. Action methods are defined in several objects that we call controllers. Open
thehelloworld/app/controllers.scala
source file:package controllers import play._ import play.mvc._ object Application extends Controller { import views.Application._ def index = { html.index("Your new Scala application is ready!") } }
-
The default
index
action is simple: it invoke theviews.Application.html.index
template and returns the generated HTML. Using a template is the most common way (but not the only one) to generate the HTTP response. Templates are special Scala source files that live in the/app/views
directory. -
Open the
helloworld/app/views/Application/index.scala.html
file:@(title:String) @main(title) { @views.defaults.html.welcome(title) }
The first line defines the template parameters: a template is a function that generates
play.template.Html
return value. In this case, the template has a single title parameter of type String, so the type of this template is(String) => Html
.Then this template call another template called main, that take two parameters: a String and an Html block.
-
Open the
helloworld/app/views/main.scala.html
file that defines the main template:
@(title:String = "")(body: => Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
<link rel="stylesheet" href="@asset("public/stylesheets/main.css")">
<link rel="shortcut icon" href="@asset("public/images/favicon.png")">
<script src="@asset("public/javascripts/jquery-1.5.2.min.js")"></script>
</head>
<body>
@body
</body>
</html>
Lift vs. Play
- Architecture: Play is based on MVC architecture and lift is basically View-first design approach. View First: View first simply means the view is what drives the creation or discovery of the view model. In view first scenarios, the view typically binds to the view model as a resource, uses a locator pattern.
- Productivity: Play is better than lift because of its learning curve.
- Security : Lift is better than any other framework
- Templates : Lift is better because you can really split up front-end dev work and back-end work
- Refactoring / maintainability : Lift is better : a MVC isn’t as good as a View-first design for that.
- Scalability : Play is slightly better and can be hosted on most cloud PaaS. Lift scales very well but you will need sticky sessions.
- Documentation : Play’s documentation is better.
- Activity : Play is more active because its more attractive for beginners.\
- Stateless/Stateful : Lift is very clear about where you need state and where you don’t. Lift can support stateless, partially stateful, and completely stateful apps. On a page-by-page and request-by-request basis, a Lift app can be stateful or stateless.
- Build environment: Lift uses Maven, sbt, Buildr, and even Ant. Lift is agnostic about the build environment and about the deploy environment (JEE container, Netty, whatever). This is important because it make Lift easier to integrate with the rest of your environment.
- Programming language: Play support java as well as scala but lift only supports scala language.
- Template language: Play uses groovy, Japid, Scala template engine as its template language while Liftweb uses HTML 5 its template language.
Conclusion
Scala designed to express common programming patterns in a concise, elegant, and type-safe way.
Scala is often compared with Groovy and Clojure, two other programming languages also built on top of the JVM. Among the main differences are:
Compared with Clojure
cala is statically typed, while both Groovy and Clojure are dynamically typed. This adds complexity in the type system but allows many errors to be caught at compile time that would otherwise only manifest at runtime, and tends to result in significantly faster execution.
Compared with Groovy
Compared with Groovy, Scala has more changes in its fundamental design. The primary purpose of Groovy was to make Java programming easier and less verbose, while Scala (in addition to having the same goal) was designed from the ground up to allow for a functional programming style in addition to object-oriented programming, and introduces a number of more “cutting-edge” features from functional programming languages like Haskell that are not often seen in mainstream languages
References :
- Official Website http://www.scala-lang.org/
- http://www.scala-lang.org/node/25
- http://www.codecommit.com/blog/scala/roundup-scala-for-java-refugees
- http://www.scala-blogs.org/2007/12/dynamic-web-applications-with-lift-and.html
- http://stackoverflow.com/questions/7468050/how-to-create-a-simple-web-form-in-scala-lift
- SNIPET - http://simply.liftweb.net/index-3.4.html
- Comet - https://www.assembla.com/spaces/liftweb/wiki/Comet_Support
- Play - http://www.playframework.com/
This article is also supported by my friend Dhruv Bansal
#scala #java #introduction #language #play #lift #spring #comparison #technology