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.

Further simplifying creating groovy DSL’s

Of the many ways of writing a DSL in groovy I prefer the approach that is taken in
a Groovy DSL from scratch in 2 hours. That article describes a general way to create a DSL and you don’t have to write too much code for it. Moreover it takes the groovy Script as a base of the DSL which is really quite powerful. But there’s still too much unnecessary complexity that you will have to deal with if you want to create a DSL (see the code dealing with ExpandoMetaClass, closures and delegates in the article).

The goal of my experiment is to further simplify creating a DSL. I want to adapt groovy Scripts in such a way that it becomes easy to access the parts of a script and use them to construct your DSL.
For this reason I choose to combine scripts with Expando’s in such a way that closures become accessible as Expando’s in a recursive way. The class that adapts scripts like this is ExpandoDsl.

This post shows what you have to write to create a DSL using (the current version of) ExpandoDsl. I will simply take the architecture example from a Groovy DSL from scratch in 2 hours so it’s easy to compare the code you have to write. Note though that I didn’t rewrite the architecture DSL completely, but it’s enough to make Steven’s example working and it should give you a good idea of what you need to write to create a DSL.

Here is the code:

package nl.rintcius.example.dsl.architecture

import com.seventytwomiles.architecturerules.configuration.Configuration
import com.seventytwomiles.architecturerules.domain.SourceDirectory
import com.seventytwomiles.architecturerules.domain.Rule
import com.seventytwomiles.architecturerules.services.CyclicRedundancyServiceImpl
import com.seventytwomiles.architecturerules.services.RulesServiceImpl

import org.apache.log4j.*

import nl.rintcius.groovy.ExpandoDsl

public class GroovyArchitecture {

    static void main(String[] args) {
        BasicConfigurator.configure()
        LogManager.rootLogger.level = Level.INFO

        runArchitectureRules()
    }

    static void runArchitectureRules() {
        runArchitectureRules(new File("architecture.groovy"))
    }

    static void runArchitectureRules(File dsl) {

        Expando root = new ExpandoDsl(dsl.text).create()

        Configuration configuration = createConfiguration(root.architecture)

        new CyclicRedundancyServiceImpl(configuration).performCyclicRedundancyCheck()
        new RulesServiceImpl(configuration).performRulesTest()
    }

    static Configuration createConfiguration(Expando expando) {
        Configuration configuration = new Configuration()
        configuration.doCyclicDependencyTest = true
        configuration.throwExceptionWhenNoPackages = true

        expando.properties.each() { key, value ->
            if (key == "jar") { configuration.addSource( new SourceDirectory(value.value, true)) }
            else if (key == "rules") { createRules(value).each() { rule -> configuration.addRule(rule)} }
        }
        configuration
    }

    static List createRules(Expando expando) {
        expando.properties.collect() { key, value ->
            createRule(key, value)
        }
    }

    static Rule createRule(String ruleName, Expando expando) {
        Rule rule = new Rule(ruleName)
        expando.properties.each() { key, value ->
            if (key == “comment”) { rule.comment = value }
            else if (key == “violation”) { rule.addViolation(value.value) }
            else if (key == “package”) { rule.addPackage(value.value) }
        }
        rule
    }
}

As you can see, the code is quite easy to follow. All you have to do is build the root Expando via
new ExpandoDsl(text).create()
and then traverse the Expando’s via expando.propertes and build your structure.

Finally, apart from ExpandoDsl there’s also ExpandoBuilder if you prefer the more restrictive builder syntax.

Let me know what you think of it!

Per class custom serialization in GWT

Need to do custom RPC serialization for a class in GWT?

Here’s how. E.g. for the class my.example.MyObject create a class named my.example.MyObject_CustomFieldSerializer. And then implement

    public static void serialize(SerializationStreamWriter streamWriter, MyObject myObject)
        throws SerializationException {}

    public static void deserialize(SerializationStreamReader streamReader, MyObject myObject)
        throws SerializationException {}

    //This method is optional
    public static MyObject instantiate(SerializationStreamReader streamReader)
        throws SerializationException {}

For more info, see CustomFieldSerializer (somehow this page didn’t show up when I googled for it, only after I knew the term was CustomFieldSerializer).

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).

Faster finding with Lenzcape’s searchbar

Next to searching from the Lenzcape application, you can also use the search plugin to search directly from the browser’s searchbar. This is how I am using Lenzcape myself usually.

The searchbar is particularly easy when you know the area that you want to search (that’s the lenz in lenzcape’s terminology). Further, the more you need to search in a specific area, the more it will pay off to create a lenz for that area.

Lenzcape’s searchbar in Firefox

To illustrate what I mean, let’s take grails as an example. I used grails to develop Lenzcape, so I am often searching grails related stuff. The base lenz for grails is “dev/grails” and following the search syntax you separate the lenz part of the query and the terms that you want to search for with a “)”. In this way you can type dev/grails ) redirect in the searchbar and it will search for redirect just in the grails area.

But you can also search more specific grails topics such as:

These lenzes all work for you as well because they are predefined. But you can also extend lenzes by integrating them with your own bookmarks. For example, I have included a few grails blogs with tag dev/grails/blog to my personal bookmarks. In this way I can search my bookmarked grails blogs via dev/grails/blog ) redirect. Note that if you type this using the search bar you will get no results unless you have also added bookmarks with tag “dev/grails/blog”.

Building your own lenzes in Lenzcape

In a former post I wrote that I would show how you can build your own lenzes in Lenzcape.

Initially I intended to show it in a blog post, but later when I got the idea to make a live demo, I thought it would be clearer (and cooler) to include it in the live demo. So check out the live demo if you want to see how you can build your own lenzes!

Redesigned version of Lenzcape now live

I have been busy redesigning Lenzcape. After the initial tryout version, I think the current state of this version is beta. Have a look at it and make sure you don’t miss the live demo.

Thanks to everyone who provided me feedback about the initial version. This has been really helpful to me. I look forward to hear what you think about this new version.

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…

Using Lenzcape to make search more efficient and effective

The traditional tools that are used to find your little gem on the web are the general search engine and the bookmark manager. With Lenzcape you can combine the power of bookmarking and searching. It allows you to search through the pages of your favorite, bookmarked sites in such a way that you are able to find your gem more effectively and efficiently. An example is probably the best way to understand how this is done exactly. So let me explain via an example.

The recipe example

Let’s take recipes as an example and suppose that we want to try out a new recipe with spinach tonight.

We will first discuss how that is usually done (i.e. via a general search engine, your bookmarks or combination of those). And then I’ll show you how you can improve on this using Lenzcape.

Finding a recipe via your general search engine

Probably, the first thing you will do is go to your favorite search engine and type something like “recipe spinach”. The results at google will show you all kinds of recipe sites of which most of them will actually contain recipes.

But you recognize the problems:

  • It takes time to scan through the google hits and filter the good sites from the bad ones.
  • There may be great sites beyond the result pages that you check out, but you will hardly find the time to view anything beyond the first 2 result pages.
  • Moreover, when you are on the result page that you do visit, you’ll get to see only a small excerpt, so you need to do your filtering based on very incomplete information.
  • After this, you spend time on the sites that you have selected to find the information you want. This is a diverse set of sites and most of them will be unknown to you, so it will cost you time to get acquainted with each of these sites and get to the real information.
  • And when it is time to make your choice, you will probably have many tabs open, so you spend time here as well finding the right tabs in your browser again and revisiting your hot picks.

And then finally you will have your recipe.

Finding a recipe via your bookmark manager

If cooking is a hobby of you then you will probably also have bookmarked some of your favorite recipe sites. So you can look up these bookmarks in your bookmark manager and search for some recipes from there. The advantage of using bookmarks over the search engine is that you know that these are all quality recipe sites and that each of them will lead you to good candidate recipes. So no rubbish sites to browse through. You may even know the structure of these sites so you will get to the recipes faster.

But there are still some major problems:

  • First, you will have to find all of the sites of your topic in your bookmark manager.
  • And then you will have to go through all of these bookmarked sites individually to select your recipe, in the same way as you did via the general search engine.

Finding a recipe via Lenzcape

Now compare this with how you will find spinach recipes via Lenzcape. This is the first page that Lenzcape returns.

You can see it live here

See the difference? Lenzcape immediately returns spinach recipes, the exact information that you are looking for! No need to go to several sites and separate the garbage from the gems. All you have to do is pick your recipe.

The advantages of using Lenzcape:

  • No need to filter out the bad sites because they are not returned.
  • The query results are of much higher quality. They lead you straight to the gems.
  • Because of this there’s no need to go and visit all the individual sites and find your way (or rather their way) to the information that you are after.
  • Using the bookmark manager, you will only use a few of your bookmarks to find your recipe. Browsing through more sites will simply cost too much time. Lenzcape, on the other hand scales just fine with the number of sites that you have bookmarked.
  • Similarly, using a general search engine, you will only tend to consider sites that are on the first result page or maybe the second if you have some spare time. When you use Lenzcape you will probably notice that you will have time to look at more pages, because the information that you are looking for is outlined nicely for you.

Zooming in: finding a soup recipe

The screenshot shows that there’s a soup and a dessert lenz under my recipes.
This shows another of Lenzcape’s features: you can zoom in for more specialized searches and zoom out for more general searches.

For example, these are the results when you are looking for spinach soups. You see that all the main dishes with spinach are gone, just soups with spinach are returned.

(See it live here)

When to use Lenzcape

Lenzcape is not meant for all types of searches. Generally, topics that you don’t bother to have any bookmarks for, you will probably also not need a special search engine for (although there may be a popular lenz defined for that).

In contrast, it is a tool that makes the pages of your bookmarked sites fully searchable. Where Lenzcape shines are topics that you often need to get back to, either for your profession or hobby. On these topics you typically will have bookmarks. And the more bookmarks you have on these topics, the more advantageous Lenzcape is.

Other examples are:

  • find an encyclopedia article
  • find a definition of a word
  • find a book title
  • find books that have their full texts on the web (compare with the one above)
  • find a software library

All of these are already included in the Lenzcape application, ready to be used.

How you can build your own lenzes

In the next post I will show you how you can create and manage lenzes with Lenzcape (Update: this is now part of the live demo). It is really not difficult, it’s very much like bookmarking, but there are a few things that you should know to make full use of Lenzcape.

It is also not a lot of work to get started. My recipe search engine that was used for this example contains just 15 bookmarks and that’s including the dessert and soup sublenzes.

By the way. I have added the recipe lenz as a popular lenz on Lenzcape application (hobby > recipe). Bon appetit!

©2006 - 2012 Rintcius Blok