A recipe to integrate Lift in an existing Spring-based web application

This is a post that summarizes how you can integrate Liftweb in an existing Spring-based web application.
The description is based on an actual example project of which the code is available at the Scala Spring project at Google code.

Before we start with the recipe, first some notes about the assumptions for this integration:

  • This recipe assumes Lift 1.0.2 and is about putting Lift’s webkit module to use (Lift also has modules for data access for example, but we will still use Spring for data access).
  • It also assumes that all Spring objects that the Lift-based code needs to access are available in the root Spring ApplicationContext. So in the example project they are available in applicationContext-jdbc.xml as opposed to the servlet specific ApplicationContext petclinic-servlet.xml.

Ok, the recipe:

  1. Specify the necessary dependencies.
            <properties>
                    <scala.version>2.7.5</scala.version>
                    <lift.version>1.0.2</lift.version>
            </properties>
    
            <dependencies>
                    <dependency>
                            <groupId>org.scala-lang</groupId>
                            <artifactId>scala-compiler</artifactId>
                            <version>${scala.version}</version>
                    </dependency>
                    <dependency>
                            <groupId>org.scala-lang</groupId>
                            <artifactId>scala-library</artifactId>
                            <version>${scala.version}</version>
                    </dependency>
                    <dependency>
                            <groupId>net.liftweb</groupId>
                            <artifactId>lift-webkit</artifactId>
                            <version>${lift.version}</version>
                    </dependency>
                    <dependency>
                            <groupId>net.liftweb</groupId>
                            <artifactId>lift-util</artifactId>
                            <version>${lift.version}</version>
                    </dependency>
            </dependencies>
    

    See: pom.xml

  2. Add a filter and filter-mapping to the web.xml. For example:
    	<filter>
    		<filter-name>LiftFilter</filter-name>
    		<filter-class>net.liftweb.http.LiftFilter</filter-class>
    	</filter>
    
    	<filter-mapping>
    		<filter-name>LiftFilter</filter-name>
    		<url-pattern>lift/*</url-pattern>
    	</filter-mapping>
    

    See: web.xml

  3. In Lift’s Boot class configure where Lift should look for snippets. For example:
    LiftRules.addToPackages("org.springframework.samples.petclinic.lift")

    See Boot.scala

  4. Create a Lift template
    <lift:surround with="default" at="content">
      <head><title>Owner</title></head>
    
      <lift:OwnerSnippet.add form="post">
      <h2><owner:newText/>Owner:</h2>
      <table>
        <owner:firstName />
        <owner:lastName />
        <owner:address />
        <owner:city />
        <owner:telephone />
        <owner:submit />
      </table>
      </lift:OwnerSnippet.add>
    </lift:surround>
    

    See ownerForm.html. This particular template uses a default template via the lift:surround element to wrap it in some standard html, but you can organize it any way you like.

  5. And finally a snippet:
    class OwnerSnippet {
    
      // Set up a requestVar to track the object for edits and adds
      object ownerVar extends RequestVar(new Owner())
      def owner = ownerVar.is
    
      def add (xhtml : NodeSeq) : NodeSeq = {
    
        def doAdd () = {
          // Reusing the spring validator code
          val result = new MapBindingResult(new HashMap(), "owner")
          new OwnerValidator().validate(owner, result)
          LiftUtils.toLiftErrors(result)
          if (!result.hasErrors()) {
            try {
              LiftUtils.clinic.storeOwner(owner)
              S.redirectTo("/owner.do?ownerId=" + owner.id)
            } catch {
              case e : DataAccessException => error("DataAccessException")
            }
          }
        }
    
        // Hold a val here so that the "id" closure holds it when we re-enter this method
        val currentId = owner.id
    
        val submitText = if (owner.isNew) "Add Owner" else "Update Owner"
    
        bind("owner", xhtml,
         "newText" -> (if (owner.isNew) "New " else ""),
         "id" -> SHtml.hidden(() => owner.id = currentId),
         "firstName" -> LiftUtils.field("First Name: ", owner.firstName, owner.firstName = _, "size" -> "30", "maxlength" -> "80", "id" -> "firstName"),
         "lastName" -> LiftUtils.field("Last Name: ", owner.lastName, owner.lastName = _, "size" -> "30", "maxlength" -> "80", "id" -> "lastName"),
         "address" -> LiftUtils.field("Address: ", owner.address, owner.address = _, "size" -> "30", "maxlength" -> "80", "id" -> "address"),
         "city" -> LiftUtils.field("City: ", owner.city, owner.city = _, "size" -> "30", "maxlength" -> "80", "id" -> "city"),
         "telephone" -> LiftUtils.field("Telephone:", owner.telephone, owner.telephone = _, "size" -> "20", "maxlength" -> "20", "id" -> "telephone"),
         "submit" -> <tr><td><p class="submit"> { SHtml.submit(submitText, doAdd) } </p></td></tr>
        )
      }
    
    }
    

Note that in this example we are reusing the validation code that was originally written for Spring (line 10-14).

Also note that it is up to you whether you define your code as a template or snippet. E.g. it would be easy to translate the ownerForm template into a snippet, or vice versa to move more code into the template.

Furthermore, check out the nifty way how Lift enables you to write the add method. What I especially like is the way the type safe way the owner is constructed (lines 4 and 5), how binding works (lines 29 and further ) and the way Scala and Lift allow you to implement a form submit (see line 37 for the call to doAdd and the method definition of doAdd starting at line 9).

On the other side, a Spring controller allows you your dependencies to be injected whereas in Lift you need to call out to obtain the objects you require. For example, in the Spring controller AddOwnerForm.scala we have a setClinic method that injects a Clinic. On the other side, in the Lift snippet we need to call out to the ApplicationContext via the ServletContext to obtain the Clinic object (see line 16 LiftUtils.clinic and it’s implementation).

By the way, there has been an interesting discussion about dependency Injection in Lift. Read that and decide what your opinion is.

WolframAlpha is live

Just played around a bit with WolframAlpha.

I can see it has added value especially for scientists and engineers. It’s a kind of Mathematica with a web front end and a large dataset to obtain the information from. Its use will largely be depending on the quantity (and quality of course) of the underlying dataset. To give you an impression of its current state, the data it has of Balkenende (Prime Minister of the Netherlands) is still limited (what is his salary?) and nothing compared to the data that is provided on Wikipedia.

On the other hand, it’s quite nice to be able to quickly see some math plots and it’s also good in doing conversions and quick calculations such as 3 feet or time in tokyo.

All in all, I think I will use WolframAlpha every now and then as a companion to Wikipedia.

A new kind of search?

After the old NKS, Wolfram is about to present another (and better?) NKS version to the world. A new kind of search that is surely making me curious! Hope it will live up to my expectations when it’s getting live.

See this preview (the video is low quality but gives an impression).

Getting the class attribute of an element in GWT

Spent a while on solving this one…

For the new version of my GWT application, I needed to get the class attribute of an element.
This code was working fine in Firefox:

    HTML html = new HTML(text);
    NodeList links = html.getElement().getElementsByTagName(”a”);
    for (int i = 0; i < links.getLength(); i++) {
      com.google.gwt.user.client.Element link =
        (com.google.gwt.user.client.Element) links.getItem(i);

      Log.info(link.getAttribute("class"));
    }

However, when I started testing other browsers this appeared not to work in Internet Explorer.
So I started trying some alternatives:

      Log.info(DOM.getElementAttribute(link, "class"));
      // Chrome & FF: ok   IE: ""

      Log.info( DOM.getElementProperty(link, "class"));
      //Chrome, FF& IE: null

      Log.info(link.getAttribute("class"));
      //Chrome & FF: ok   IE: ""

      Log.info(getAttribute(link, "class"));
      //Chrome & FF: ok   IE: null

      Log.info(link.getClassName());
      //Chrome, FF & IE: ok 
    }

    public static native String getAttribute(Element elem, String attr)
    /*-{
       return elem.getAttribute(attr);
    }-*/; 

At last link.getClassName() did the trick, but it took me some time before I realized that class is treated as an exceptional attribute in IE and that this method did exist at all!

Would be nice if there was a mechanism (assert?) that pointed to this method when getAttribute is called with class (and what about id?). But for now I hope google is your friend when you stumble on this issue…

©2006 - 2012 Rintcius Blok