Showing posts with label liftweb mapper. Show all posts
Showing posts with label liftweb mapper. Show all posts

Friday, 16 November 2012

Hacking on liftweb 2.5 and sbt 0.12



STEP 1 Download the ‘Lift Basic’ template
prayag@prayag:/backup/workspace.programming/workspace.scala$ git clone git://github.com/lift/lift_25_sbt.git
Cloning into 'lift_25_sbt'...
remote: Counting objects: 881, done.
remote: Compressing objects: 100% (506/506), done.
remote: Total 881 (delta 301), reused 839 (delta 259)
Receiving objects: 100% (881/881), 3.03 MiB | 20 KiB/s, done.
Resolving deltas: 100% (301/301), done.

Going through the liftweb app structure
prayag@prayag:/backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29$ ls -l lift_basic/
total 1100
-rw-rw-r-- 1 prayag prayag    1159 Nov 16 16:33 build.sbt
drwxrwxr-x 2 prayag prayag    4096 Nov 16 16:33 project
-rwxrwxr-x 1 prayag prayag     116 Nov 16 16:33 sbt
-rw-rw-r-- 1 prayag prayag     137 Nov 16 16:33 sbt.bat
-rw-rw-r-- 1 prayag prayag 1103617 Nov 16 16:33 sbt-launch-0.12.jar
drwxrwxr-x 4 prayag prayag    4096 Nov 16 16:33 src

There is sbt-launch-0.12.jar, which means the Lift Basic template comes with a SBT launcher, so there’s no need to install sbt separately.

The src/main structure is 
prayag@prayag:/backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29$ ls -l lift_basic/src/main/
total 12
drwxrwxr-x 3 prayag prayag 4096 Nov 16 16:33 resources
drwxrwxr-x 4 prayag prayag 4096 Nov 16 16:33 scala
drwxrwxr-x 6 prayag prayag 4096 Nov 16 16:33 webapp

The MVC looking architecture of liftweb is 
prayag@prayag:/backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29$ ls -l lift_basic/src/main/scala/code/
total 20
drwxrwxr-x 2 prayag prayag 4096 Nov 16 16:33 comet
drwxrwxr-x 2 prayag prayag 4096 Nov 16 16:33 lib
drwxrwxr-x 2 prayag prayag 4096 Nov 16 16:33 model
drwxrwxr-x 2 prayag prayag 4096 Nov 16 16:33 snippet
drwxrwxr-x 2 prayag prayag 4096 Nov 16 16:33 view

STEP 2 : Building an app
Add Lift and Jetty to project dependencies:
#The build.sbt file is

name := "Lift 2.5 starter template"

version := "0.0.1"

organization := "net.liftweb"

scalaVersion := "2.9.1"

resolvers ++= Seq("snapshots"     at "http://oss.sonatype.org/content/repositories/snapshots",
                "releases"        at "http://oss.sonatype.org/content/repositories/releases"
                )

seq(com.github.siasia.WebPlugin.webSettings :_*)

scalacOptions ++= Seq("-deprecation", "-unchecked")

libraryDependencies ++= {
  val liftVersion = "2.5-M3"
  Seq(
    "net.liftweb"       %% "lift-webkit"        % liftVersion        % "compile",
    "net.liftweb"       %% "lift-mapper"        % liftVersion        % "compile",
    "net.liftmodules"   %% "lift-jquery-module" % (liftVersion + "-2.0"),
    "org.mortbay.jetty" % "jetty" % "6.1.22"    % "container",
    "org.eclipse.jetty" % "jetty-webapp"        % "8.1.7.v20120910"  % "container,test",
    "org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container,test" artifacts Artifact("javax.servlet", "jar", "jar"),
    "ch.qos.logback"    % "logback-classic"     % "1.0.6",
    "org.specs2"        %% "specs2"             % "1.12.1"           % "test",
    "com.h2database"    % "h2"                  % "1.3.167"
  )
}

The project/plugins.sbt file is 
libraryDependencies <+= sbtVersion(v => "com.github.siasia" %% "xsbt-web-plugin" % "0.12.0-0.2.11.1")

//Uncoment this line to enable the sbt idea plugin
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.1.0")

//Uncoment this line to enable the sbt eclipse plugin
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0")


The sbt script is 

prayag@prayag:/backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29/lift_basic$ sudo vi sbt


java -Xmx1024M -Xss2M -XX:MaxPermSize=512m -XX:+CMSClassUnloadingEnabled -jar `dirname $0`/sbt-launch-0.12.jar "$@"

The command ‘sbt update ~jetty-run’ will download all necessary libraries (Scala, Lift, Jetty, etc) like mvn install does in maven, compile the application, and then launch Jetty as an embedded application – there’s no need to install Jetty separately, (~jetty-run isn't working in my case).
prayag@prayag:/backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29/lift_basic$ ./sbt update ~jetty-run


STEP 3 : Run app with sbt
sbt tasks can be viewed with $ sbt tasks command.
prayag@prayag:/backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29/lift_basic$ ./sbt
> update
> container:start
[info] Compiling 4 Scala sources to /backup/workspace.programming/workspace.scala/lift_25_sbt/scala_29/lift_basic/target/scala-2.9.1/classes...
[info] 'compiler-interface' not yet compiled for Scala 2.9.1.final. Compiling...
[info]   Compilation completed in 37.636 s
2012-11-16 23:14:24.820:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
[info] jetty-6.1.22
[info] NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet
[info] Started SelectChannelConnector@0.0.0.0:8080
[success] Total time: 56 s, completed 16-Nov-2012 23:14:30

Open http://localhost:8080 in a web browser to see the application running.


References
Getting Started, https://www.assembla.com/spaces/liftweb/wiki/Getting_Started

Sunday, 28 October 2012

Connecting Liftweb to MySQL

After successfully creating a liftweb app, here is how to connect liftweb to mysql and get things done.

The structure of the liftweb app is as follows:

prayag@prayag:~/workspace_lift/gwitter/gwitter$ ls -l
total 92
-rw-rw-r-- 1 prayag prayag 18432 Oct 28 10:45 lift_proto.db.h2.db
-rw-rw-r-- 1 prayag prayag 42000 Oct 28 10:45 lift_proto.db.trace.db
-rw-rw-r-- 1 prayag prayag  7459 Oct 28 11:10 pom.xml
drwxrwxr-x 3 prayag prayag  4096 Oct 16 12:22 project
drwxrwxr-x 4 prayag prayag  4096 Oct 16 12:22 src
drwxrwxr-x 9 prayag prayag  4096 Oct 28 11:14 target

STEP 1 configure db properties
prayag@prayag:~/workspace_lift/gwitter/gwitter$ sudo kate src/main/resources/props/default.props 

# Properties in this file will be read when running in dev mode
db.dialect=org.hibernate.dialect.MySQL5Dialect
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/Gwitter
db.user=root
db.password=root

STEP 2 configure Database Vendor in Boot.scala
prayag@prayag:~/workspace_lift/gwitter/gwitter$ sudo kate src/main/scala/bootstrap/liftweb/Boot.scala

/**
 * A class that's instantiated early and run.  It allows the application
 * to modify lift's environment
 */
class Boot {
  def boot {
    //add the following code in method boot
    if (!DB.jndiJdbcConnAvailable_?) {
      println("jndiJdbcConnAvailable_ : " + 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)
    }//end of jndiJdbcConnAvailable_
 }//end of boot
}

STEP 3 Add maven dependency for mysql in pom.xml
<dependencies>
   ....
   .....
   .......
    <!-- for LiftConsole -->
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-compiler</artifactId>
      <version>${scala.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- mysql dependency-->
    <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.17</version>
     <type>jar</type>
    </dependency>
  </dependencies>

STEP 4 Update maven dependency
prayag@prayag:~/workspace_lift/gwitter/gwitter$ mvn install

STEP 5 - Have a look at model
http://exploring.liftweb.net/master/index-2.html#lst:PocketChange-User-entity

prayag@prayag:~/workspace_lift/gwitter/gwitter$ sudo kate src/main/scala/com/zam/gwitter/model/User.scala

5.A)
Create a User class extending the Mapper base class MegaProtoUser, which provides default fields and methods
for a User.
class User extends MegaProtoUser[User] {
  def getSingleton = User // what's the "meta" server
                          // reference to the companion object below

  // define an additional field for a personal essay
  object textArea extends MappedTextarea(this, 2048) {
    override def textareaRows  = 10
    override def textareaCols = 50
    override def displayName = "Personal Essay"
  }
  
  //def findUser : User = 
    /User.find(By(User.id, this.id))
}

5.B)
Create a "companion object" to the User class (above).
The companion object is a "singleton" object that shares the same name as its companion class.
It provides global (i.e. non-instance) methods and fields, such as find, dbTableName, dbIndexes, etc.
object User extends User with MetaMegaProtoUser[User] {
  override def dbTableName = "User" // define the DB table name, I love to use singular names for tables
  override def screenWrap = Full( <lift:surround with="default" at="content">
           <lift:bind />
       </lift:surround>
      )
  // define the order fields will appear in forms and output
  override def fieldOrder = List(id, 
                                 firstName, 
                                 lastName, 
                                 email,
                                 locale, 
                                 timezone, 
                                 password, 
                                 textArea)

  // comment this line out to require email validations
  override def skipEmailValidation = true
}

STEP 6 Create database Gwitter at mysql server
mysql>create database Gwitter;

STEP 7 Run the app
prayag@prayag:~/workspace_lift/gwitter/gwitter$ mvn jetty:run

I get the message like the following in between :
[INFO] Scanning for projects...
...
...
...
11:18:52.922 [main] DEBUG net.liftweb.util.Props - Loaded key/value properties from resource /props/default.props
11:18:53.017 [main] DEBUG net.liftweb.mapper.MetaMapper - Initializing MetaMapper for User
11:18:53.018 [main] DEBUG net.liftweb.mapper.MetaMapper - Created FieldFinder for interface net.liftweb.mapper.MappedField
11:18:53.787 [main] DEBUG net.liftweb.db.ProtoDBVendor - Created new pool entry. name=ConnectionIdentifier(lift), poolSize=1
11:18:53.830 [main] DEBUG net.liftweb.mapper.Schemifier - Starting schemify. write=true, structureOnly=false, dbId=ConnectionIdentifier(lift), schema=esewa@10.20.222.254, tables=List(users)
11:18:53.832 [main] DEBUG net.liftweb.mapper.Schemifier - Running beforeSchemifier on table users
11:18:53.992 [main] DEBUG net.liftweb.mapper.Schemifier - Executing DDL statements
11:18:53.993 [main] DEBUG net.liftweb.mapper.Schemifier - Running afterSchemifier on table users
11:18:53.995 [main] DEBUG net.liftweb.db.ProtoDBVendor - Released connection. poolSize=1
2012-10-28 11:18:54.232:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 5 seconds.

STEP 8 Check database
prayag@prayag:~$ mysql -u root -p
Enter password:

mysql> use Gwitter;

mysql> show tables;
+------------------------+
| Tables_in_Gwitter |
+-----------------------+
| users                      |
+-----------------------+
1 row in set (0.00 sec)


mysql> desc users;
+------------------+-------------------------+------+-----+-------------+--------------------+
| Field            | Type       | Null | Key | Default    | Extra                 |
+-------------------+-------------------------+------+-----+------------+--------------------+
| id                     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| firstname         | varchar(32)              | YES  |     | NULL      |                           |
| lastname          | varchar(32)              | YES  |     | NULL      |                           |
| email               | varchar(48)               | YES  | MUL | NULL|                           |
| locale              | varchar(16)               | YES  |     | NULL      |                           |
| timezone         | varchar(32)              | YES  |     | NULL      |                           |
| password_pw  | varchar(48)              | YES  |     | NULL      |                           |
| password_slt   | varchar(20)             | YES  |     | NULL      |                           |
| textarea           | varchar(2048)        | YES  |     | NULL      |                           |
| uniqueid         | varchar(32)              | YES  | MUL | NULL|                           |
| validated         | tinyint(1)                  | YES  |     | NULL      |                           |
| superuser        | tinyint(1)                 | YES  |     | NULL      |                           |
+-----------------+-------------------------+-------+-----+------------+---------------------+
12 rows in set (0.01 sec)




REFERENCES
1 - How to create database connection with MySQL in Liftweb Scala, available at http://www.jooiner.com/how-to-create-database-connection-with-mysql-in-liftweb-scala/

2 - 2.1 Defining the Model, http://exploring.liftweb.net/master/index-2.html#lst:PocketChange-User-entity

3 - Scala/Lift Database Connections, http://stackoverflow.com/a/5026630/432903

4 - Mapper, https://www.assembla.com/spaces/liftweb/wiki/Mapper

5 - pocketchange app, https://github.com/tjweir/pocketchangeapp/tree/master/PocketChange/src/main

6 - How to create Simple Mini Blog With LiftWeb, https://github.com/slashmili/LiftWeblogIn30Mins/wiki/SimpleMiniBlog