Posts Tagged ‘Scala’

Configuring Persistence for Lift Web Applications

Sunday, May 29th, 2011

Generating a basic Lift web application using Maven (see Using Maven and Eclipse to generate Scala Lift Web Applications) creates a project that by default uses a H2 database. The generated application provides three obvious options for configuring persistence. The starting point is Boot.scala (located in src/main/scala/bootstrap/liftweb/Boot.scala).

In examples below we look at:

  • how H2 is specified as the default database in Boot.scala
  • using a properties file to specify a different database (e.g. MySQL)
  • using JNDI to specify a third database (e.g. PostgreSQL).

The Default Database

The code fragment below from the generated Boot.scala file determines that:

  • if there is no JNDI entry for the database and
  • there are no JDBC entries specified in the properties file
  • then connect to a H2 database using JDBC driver class “org.h2.Driver” and JDBC url “jdbc:h2:lift_proto.db; AUTO_SERVER=TRUE”.
class Boot {
def boot {
  if (!DB.jndiJdbcConnAvailable_?) {
    val vendor =
       new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
	   Props.get("db.url") openOr
	  "jdbc:h2:lift_proto.db;AUTO_SERVER=TRUE",
	   Props.get("db.user"), Props.get("db.password"))

    LiftRules.unloadHooks.append(vendor.closeAllConnections_! _)

    DB.defineConnectionManager(DefaultConnectionIdentifier, vendor)
  }
 ...
}

Since the property file is not automatically generated with JDBC properties the H2 database becomes the default.

Updating the Maven POM File

When configuring for a database other than H2 the Maven POM file needs to be updated so that a jar file containing the appropriate JDBC driver is available at runtime. The following adds the JDBC drivers for both MySQL and Postgres.

<project ... >
   ...
  <dependencies>
    <dependency>
     ...
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.2.138</version>
      <scope>runtime</scope>
    </dependency>
    <!--  Added for MySQL datasource -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.15</version>
      <scope>runtime</scope>
    </dependency>
    <!--  Added for PostgreSQL datasource -->
    <dependency>
    	<groupId>postgresql</groupId>
    	<artifactId>postgresql</artifactId>
    	<version>9.0-801.jdbc4</version>
      <scope>runtime</scope>
    </dependency>
     ...
  </dependencies>
   ...
<project>

Configuring JDBC with a Properties File

Adding the property file “default.props” to the project at

  • src/main/resources/props/default.props

allows a different database to be configured by setting JDBC properties with names matching those expected in Boot.scala.

The example default.props below configures a MySQL database.

# Properties in this file will be read when running in dev mode
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/liftbasic
db.user=mysql_username
db.password=mysql_password

Using JNDI to Configure a Datasource

A JNDI configured database can be enabled by adding one additional line specifying the JNDI name of the datasource, for example:

DefaultConnectionIdentifier.jndiName = "jdbc/liftbasic"

The original generated code becomes.

def boot {
  ...
  DefaultConnectionIdentifier.jndiName = "jdbc/liftbasic"

  if (!DB.jndiJdbcConnAvailable_?) {
    val vendor =
       new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
	   Props.get("db.url") openOr
	  "jdbc:h2:lift_proto.db;AUTO_SERVER=TRUE",
	   Props.get("db.user"), Props.get("db.password"))

    LiftRules.unloadHooks.append(vendor.closeAllConnections_! _)

    DB.defineConnectionManager(DefaultConnectionIdentifier, vendor)
  }
 ...
}

A more configurable option is to replace the code just added with the following which checks to see if the JNDI datasource has been set by the “jndi.name” property in the “default.props” property file. If not “jdbc/liftbasic” is used.

DefaultConnectionIdentifier.jndiName = Props.get("jndi.name") openOr "jdbc/liftbasic"

A resource-ref element is also added to the web.xml file (i.e. src/main/webapp/WEB-INF/web.xml) to allow the container to manage the connection to the database.


<web-app>
    ...
   <resource-ref>
      	<description>Database Connection</description>
      	<res-ref-name>jdbc/liftbasic</res-ref-name>
      	<res-type>javax.sql.DataSource</res-type>
      	<res-auth>Container</res-auth>
   </resource-ref>
    ...
</web-app>

Container Specific JNDI Settings

Each server platform has its own specific way of configuring the JNDI settings that map the JNDI name read by Lift to a specific database. Below are examples for Tomcat, Jetty and the Cloudbees platform.

Tomcat

Tomcat manages JNDI settings via the Context element. The following adds a Context element to the Tomcat server.xml file ( i.e. TOMCAT_HOME/conf/server.xml),  mapping the JNDI name to a PostgreSQL database.

<Server>
  <Service>
    <Engine>
      <Host>
         ...
		<Context path="/liftbasic" docBase="liftbasic" reloadable="true" crossContext="true">
			<Resource name="jdbc/liftbasic"
			auth="Container"
			description="DB Connection"
			type="javax.sql.DataSource"
			driverClassName="org.postgresql.Driver"
			url="jdbc:postgresql://127.0.0.1:5432/postgres"
			username="postgres_username"
			password="postgres_password"
			maxActive="4"
			maxIdle="2" maxWait="-1"/>
		</Context>
        ...
      </Host>
    </Engine>
  </Service>
</Server>

Jetty

There are a number of options for configuring JNDI for Jetty. One option is to add a jetty-env.xml file to the WEB-INF directory to configure JNDI resources specifically for that webapp. The example jetty-env.xml file below configures a MySQL JNDI datasource for Jetty.

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">

	<New id="liftbasic" class="org.mortbay.jetty.plus.naming.Resource">
	    <Arg></Arg>
	    <Arg>jdbc/liftbasic</Arg>
	    <Arg>
	     <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
	                 <Set name="Url">jdbc:mysql://localhost:3306/liftbasic</Set>
	                 <Set name="User">mysql_username</Set>
	                 <Set name="Password">mysql_password</Set>
	     </New>
	    </Arg>
	   </New>
</Configure>

CloudBees

CloudBees specific configuration is placed in the cloudbees-web.xml file in the WEB-INF directory of the deployed WAR file (i.e. src/main/webapp/WEB-INF/cloudbees-web.xml).  The example below maps a CloudBees Managed MySQL datasource to the JNDI name read by Lift.

<?xml version="1.0"?>
<cloudbees-web-app xmlns="http://www.cloudbees.com/xml/webapp/1">
    <appid>lift</appid>
    <context-param>
        <param-name>application.environment</param-name>
        <param-value>prod</param-value>
    </context-param>
	<resource name="jdbc/liftbasic" auth="Container" type="javax.sql.DataSource">
	 <param name="username" value="cloudbees_mysql_username" />
	 <param name="password" value="cloudbees_mysql_password" />
	 <param name="url" value="jdbc:cloudbees://liftbasic" />
	</resource>
</cloudbees-web-app>

Using Maven and Eclipse to generate Scala Lift Web Applications

Sunday, April 24th, 2011

The Lift web framework is built on top of Scala which in turn runs on the Java Platform. Lift applications are built as WAR files and deployed to servlet containers such as Tomcat and Jetty.

The Maven archtetypes for Lift and the Scala IDE for Eclipse make it easy for a Java developer to start building and deploying Lift applications using familiar tools. Since Lift views (templates) are valid XHTML or HMTL5 the Eclipse IDE for Java EE Developers (Helios SR2) and its XML and HTML editors can be used to design Lift web interfaces.

Installing the Scala IDE and the M2Eclipse Maven plugin into the Eclipse IDE for Java EE Developers allows new Lift applications to be created by selecting a suitable Lift archtetype when creating a new Maven project.

For example the Maven command below uses the Lift basic archetype to generate a Lift project with a default H2 database, logging and user management.

mvn archetype:generate
-DarchetypeGroupId=net.liftweb -DarchetypeArtifactId=lift-archetype-basic_2.8.1
-DarchetypeVersion=2.2 -DarchetypeRepository=http://scala-tools.org/repo-releases -DremoteRepositories=http://scala-tools.org/repo-releases
-DgroupId=com._3kbo.scala -DartifactId=liftbasic -Dversion=1.0

The same Lift project can be generated from within Eclipse using the Maven new project wizard and selecting the Lift basic archetype (as shown below).

maven archetype

Apply the Scala nature to the project by first opening the project in the Scala perspective, select the project (e.g. liftbasic) in the package explorer and select  Configure | Add Scala Nature.

The application created using the Maven command line can be run in Jetty from the command line with the command:

mvn jetty:run

The web application can then be accessed at http://localhost:8080/.

Similarly the Eclipse Maven project can be run in Jetty within Eclipse by setting up and running a Runtime Configuration like the one below:

mvn jetty:run