Showing posts with label lift web. Show all posts
Showing posts with label lift web. Show all posts

Saturday, October 20, 2012

Lift Web Framework is Easy

It's ubiquituously said that the Lift web framework has a steep learning curve.  Hard to believe when

<div class="lift:surround?with=default;at=content" id="real_content">
 <h1>Welcome to your project!</h1>
 <lift:Hello.world />  
</div>
object Hello extends DispatchSnippet {
 val dispatch: DispatchIt = {
  case name => render(name) _
 }
 def render(name: String)(ignore: NodeSeq): NodeSeq = Text("Hello, " + name)
}
LiftRules.snippetDispatch.append {
 case "Hello" => id.openfx.openshop.snippet.Hello
}
simply wraps the page with the template 'default.html' and makes a snippet Hello.world lookup.

Everything in Lift is easy and transparent, I daresay. Most things can be reasoned as you write code, instead of having to read its specification. I can't quite describe it precisely, but I'll give it a shot anyway. Because Scala allows "mix in" of traits, there is, CMIIW, no hidden container-managed proxy code is needed. Let's compare this with CDI used in the JSF framework. To cater to different scopes, a CDI bean can be annotated with @RequestScoped, @SessionScoped, @ConversationScoped, etc. How does it look like when constructed? Honestly I don't know. I only know how it should work thanks to the CDI spec's documentation. But I think the container would have to create a specific proxy for each bean depending on its scope, and inject its proxy dependencies and so on. The proxy might also be different when you add @Stateful to, say, a @ConversationScoped bean.

On the other hand, in Lift, it's much simpler. Snippets are normal methods registered via the LiftRules object during boot. Request and session states are just plain objects extending either RequestVar or SessionVar, used directly by snippets. The separation between controller logic and session/request data is clear here. You know what's happening to your stuff by checking out what's inside what you're extending.

Tuesday, August 21, 2012

Around the Web

Sometime ago I checked out different approaches to web application development (in my free time.)  With Python I explored the Pyramid framework as well as Django.  With Scala I did Lift.  And lastly I explored JSF using Groovy as a replacement for Java.

Actually I was quite overwhelmed with Python.  It's not difficult to write anything in Python. 
However, to write good code in Python it should take considerably more effort and more thorough understanding of the language.  I stumbled across a lot of metaprogramming then.  I think it grossly difficult to feel secure because, with metaprogramming alongside dynamic typing, most of your application's survival depends on the condition of your gestalt.

Scala lifts much of that mental burden off me I should think.  I like Lift.  I could do more in Lift in the future.  :)

Groovy is, as I probably wrote in my previous post, somewhat in the middle when it comes to typing--a degree of static as well as dynamic typing.  It saves a lot of time and code lines.  In a way it intuitively guides me to write better code.  There can be a lot of metaprogramming too in Groovy, but it's not a show stopper.  You don't necessarily have to understand it to write good code.  Though it's pretty easy (I think compared to that in Python).  It would be much better if Java EE and relevant stuff were tailored to fit Groovy more.  And better IDE support.  And a way to filter exception stack traces (Seam Catch maybe?).

Wednesday, May 30, 2012

Resources Publishing for WTP Maven Projects

I never realised this before but apparently these Eclipse Builders work really well to avoid collision between each other.
It was nightmare having to 'clean package jboss-as:deploy' the entire EAR again and again even when change was only on the xhtml--no recompiling!
The EAR project retains its skeleton structure even without the Maven EAR plugin (which is to be expected really, duh).  Which means you can deploy, undeploy, and redeploy part or all of the EAR into your web container via the usual Add or Remove menu.  What a pleasure!

Saturday, April 7, 2012

Lift as Eclipse WTP Project

Some of us--we've never used Maven, let alone SBT.  We're used to Eclipse's default build, test, deploy, and reload features. Why limit the choices to starting up a Lift web project by requiring knowledge of either.  So here goes it:
  1. Make sure you have Eclipse with WTP (comes with the default Java EE package), Scala IDE, and IvyDE installed.  You can opt not to use IvyDE for library management by adding jars manually.  For that you can go to MvnRepository to see the required dependencies.  A basic Lift project usually relies on either lift-mapper or lift-jpa as a single parent dependency.
    One thing to note here is this issue where Scala compiler generates version-specific byte-code.  This generally means that if you use Scala 2.9.1, you have to compile your project against a version of Lift that's compiled against Scala 2.9.1 and all the Lift dependencies must also be compiled against that version of Scala.  Lift packages come with their version as their name's suffix, thus if you use Scala 2.9.1 you would pick lift-mapper_2.9.1 as the basis of your dependency resolution.
  2. In the IDE create a new Dynamic Web Project.
    Because Lift works with any servlet container that implements the Servlet 2.5 specs, chances are your favourite container will work just fine too.  Personally I would recommend using the latest release of JBoss AS.  It's quite as blazing fast as advertised and perhaps you might want to use some bleeding edge Java EE specs like JPA, CMT, and EJB to help with your software architecture.
  3. To add Scala nature, open file .project and do the following changes:
    1. Add a buildCommand with name org.scala-ide.sdt.core.scalabuilder.
    2. Add a nature with value org.scala-ide.sdt.core.scalanature.
  4. In project→Properties→Java Build Path, add Scala libraries.  Also add it to project→Properties→Deployment Assembly.
  5. Add Lift packages and their dependencies, although...
  6. If you have IvyDE installed:
    1. You can skip this if the default ibiblio Maven repository works ok for you.  It's most of the time really slow for me so I tend to use Antelink's instead.  To do this, create a file named ivysettings.xml (could be anywhere in your project) containing:
      <ivysettings>
         <settings defaultResolver='antelink'/>
         <resolvers>
            <ibiblio name="antelink" root="http://maven.antelink.com/content/repositories/central/" m2compatible="true"/>
         </resolvers>
      </ivysettings>
    2. Create an Ivy file using the wizard and add this:
      <dependencies>
         <dependency org="net.liftweb" name="lift-jpa_2.9.1" rev="2.4">
            <exclude org="org.scala-lang" matcher="glob" name="scala*" />
         </dependency>
      </dependencies>
    3. In project→properties→Java Build Path→Libraries click Add Library and select IvyDE Managed Dependencies.  Set the Ivy File, check Enable project specific settings, and set the Ivy settings path.  Also add this Ivy dependency to project→Properties→Deployment Assembly.  When you're done, Ivy will probably take a while to resolve your dependencies.  You can see its progress by displaying the Ivy Console.

  7. A Lift web project generally has this kind of folder structure:
    src
    |_main
      |_resources
      |_scala
      |_webapp
        |_images
        |_static
        |_templates-hidden
        |_WEB-INF
    |_test
      |_scala

    To do this, you will need to remove the default WebContent directory and move everything inside it into src/main/webapp.  You will also need to, in project→Properties→Java Build Path→Source, edit accordingly to point to src/main/resources as well as src/main/scala.
  8. Inside src/main/webapp/WEB-INF you need a web.xml.  This is usually generated automatically upon project creation.  Add a filter with name LiftFilter and class net.liftweb.http.LiftFilter and a filter-mapping with name LiftFilter and url-pattern /*.  You can change the name and url-pattern according to your needs.
  9. The LiftFilter by default looks for a class named Boot inside the package bootstrap.liftweb (src/main/scala/bootstrap/liftweb/Boot.scala) and executes the boot method (def boot() {...}).
    But you can also have this class anywhere else in your classpath.  To do that your Boot class needs to extend net.liftweb.http.Bootable and add the following entry in your web.xml's LiftFilter:
    <init-param>
      <param-name>bootloader</param-name>
      <param-value>path.to.your.Boot</param-value>
    </init-param>
  10. Setting up logging.
    1. I have only ever used Logback so this is the logging backend that we'll use here.  I would advise against using IvyDE to manage your Logback dependency because by default Logback depends on a lot of other libraries that you might not even use in your Lift web project (such as Groovy).  You can instead manually download Logback and add logback-access, logback-core, and logback-classic to your build path.
    2. Now you want to setup your Lift's default logging back end.  First add a logback.xml in src/main/resources.  Logback configuration doesn't have a schema so don't bother looking.  Do open this link for an example of the most basic Logback configuration.  Next open your Boot class and add the following inside the boot method:
      LiftRules.getResource("/logback.xml") match {
        case Full(url) => Logger.setup = Full(Logback.withFile(url)); case _ => println("Logback configuration not found.")
      }
  11. Next you can continue by setting up class resolution and site map and creating your first page by utilising templates and binding.  A Lift tutorial book I would totally recommend is Lift in Action by Timothy Perrett.
  12. Lastly you can build, test, and deploy your web application the way you normally do it in Eclipse.  Managing and configuring your web server and deployment are probably much easier using their default Eclipse adapter plugin compared to using Maven.