Big Data/Analytics Zone is brought to you in partnership with:

Chanwit is an Assistant Professor at School of Computer Engineering, Institute of Engineering, Suranaree University of Technology, Thailand. He is a contributor to the Grails framework, also maintains and leads development of the ZK plugin for Grails. Recently, Chanwit has been co-developing low-powered ARM-based clusters for processing Big Data using Apache Spark and Apache Hadoop. Chanwit has posted 5 posts at DZone. You can read more from them at their website. View Full User Profile

Develop a MongoDB Application with ZK & Grails

04.28.2013
| 10246 views |
  • submit to reddit

Introduction

In this article, I'll show you how to create a MongoDB application using the new version of ZKGrails, ZKGrails 2.2. This application has been developed by following Simon's MongoMaps application also on DZone. At the end of this article, you will find yourself be able to create a simple MongoDB application with ZK and Grails.

ZKGrails has been a part of the Grails eco-system since 2008. I envisioned that Grails would be a fullstack Web platform instead of a framework that supports only MVC. This idea has been a driving force behind the development of ZKGrails. Today, ZKGrails is a leading plugin, out of almost 1,000 available, that supports another View/Controller layer beyond the Grails' GSP. Also in the near future, Grails will be evolved again from a Web development platform to be a fullstack application development platform. Of course, ZKGrails will also be evolved along as a Grails' RIA profile.

Domain class and MongoDB

As usual, we start creating a ZKGrails application from the domain part of the application. Grails 2 lifted the support of persistence layer beyond Hibernate. The GORM layer of Grails 2 provides a very transparent way for us to connect to MongoDB. This means you can switch between Hibernate mapping and MongoDB just by changing plugins and re-configuring dataSources.

I'll start by creating a Grails application, setting MongoDB plugin up and pointing the dataSource to my local MongoDB instance.

$ grails create-app mongomaps
$ cd mongomaps

Find your grails-app/conf/BuildConfig.groovy and add:

compile ':mongodb:1.1.0.GA'

into the plugins { } block to install the Grails MongoDB plugin.

//
// BuildConfig.groovy
//

plugins {
    compile ':mongodb:1.1.0.GA'
}

Also inside BuildConfig.groovy, it is a good idea to turn legacyResolve true to ensure that Grails can resolve plugin dependencies correctly.

//
// BuildConfig.groovy
//

grails.project.dependency.resolution = {
    ...
    legacyResolve true
    ...
}

To make sure the MongoDB plugin is installed properly, type:

$ grails refresh-dependencies

If you've got some messages saying that the MongoDB plugin being installed, it's good to go.

Then it's time for our domain class. We are going to have a domain class for storing US Zip codes and their locations. Type the following command to create Zipcode.groovy:

$ grails create-domain-class Zipcode

Then find it under grails-app/domain/mongomaps/, open and basically copy and paste the following codes.

package mongomaps

class Zipcode {

    Integer pop
    String state
    List loc
    String city
  
    static transients = ['lat', 'lng']

    Double getLng() { loc[0] as Double }
    Double getLat() { loc[1] as Double }

    static constraints = {
        loc geoIndex: true
    }

    static mapping = {
        collection "maps"
    }

}

Let's start with the domain class' properties. There are 4 properties mapped to the MongoDB “maps” collection (see static mapping at line 19). Property pop is for population number, state is the state's name, city is the city's name. The tricky one here is loc, which is mapped as a 2-element List. Suggested by Simon's article, we also have getters for longitude (loc[0]) and latitude (loc[1]). Both are of type Double. Property loc is mapped correctly to longitude & latitude by having loc geoIndex: true in the constraints block (line 16-18).

We move next to configuring our dataSource. For a MongoDB instance on the localhost, putting the following configuration into grails-app/conf/DataSource.groovy is enough.

//
// DataSource.groovy
//

grails {
    mongo {
        host = "localhost"
        databaseName = "grails"
    }
}

What we need at the moment is, of course, a running instance of MongoDB and the test data. Installing MongoDB is relatively easy. Just goto http://mongodb.org, download and unzip. Then, run bin/mongod –dbpath=./data and you've got its instance running.

To import the test data, download “zips.js” from the following URL:

https://dl.dropbox.com/u/381580/zkgrails/zips.json

and use a MongoDB utility, mongoimport, to import the file. Do not forget that we have configured the database name to “grails” and the collection name to “maps”.

User Interface with ZK

Now we back to BuildConfig.groovy again to install the ZK plugin for Grails. Put the following line:

compile “:zk:2.2.0”

into the plugins { } block, like the following:

//
// BuildConfig.groovy
//

plugins {
    ...
    compile ':mongodb:1.1.0.GA'
    compile ':zk:2.2.0'
}

Also, we need the Google Map ZK component (for the <gmaps/> tag), which can be downloaded from here:

http://www.zkoss.org/download/zkgmaps

Download the binary, and extract gmapz.jar into ./lib directory

Then let Grails refresh all dependencies again.

$ grails refresh-dependencies

Since ZKGrails 2.1, it has introduced a new way to develop ZK applications using jQuery-style APIs. ZKGrails 2.2 improves the set of APIs in several ways, including the new UI template system.

We start the UI part by creating a ZUL file and its Composer with the following command:

$ grails create-zul index

In the generated grails-app/zul/index.zul, edit it to be like the following:

<zk xmlns="http://www.zkoss.org/2005/zul">

  <vlayout width="600px" vflex="true" apply="mongomaps.IndexComposer">

    <gmaps width="600px" vflex="true" />

    <listbox width="600px" height="280px">
      <listhead>
        <listheader label="Id"/>
        <listheader label="Name"/>
        <listheader label="State"/>
        <listheader label="Population"/>
      </listhead>
    </listbox>

    <hlayout sclass="z-valign-middle">
      <paging hflex="true" />
    </hlayout>

  </vlayout>

</zk>

The index.zul file contains 1. a Google Map component (<gmaps/>) 2. A listbox component with 4 data columns (<listbox/>) and 3. a pagination component (<paging/>) to control the display of data. Please note that we do not set any id to these components on purpose. They will be manipulated by jQuery-style CSS selectors from the associated mongomaps.IndexComposer.

Inspired by Backbone.JS, we simplified the name of our Composer base class, zk.grails.Composer, to be more intuitive in ZKGrails 2.2. The new Composer name is far easier to memorize than the old one provided by older versions of ZKGrails. Also, the new one does not require any AST transformation to add new APIs to the Composer. Nothing is to slow down the compilation process. Moreover, declaring an explicit super class makes intelli-sense or auto-completion in any IDE happy.

package mongomaps

class IndexComposer extends zk.grails.Composer {

    static PAGE_SIZE = 8

    def afterCompose = { window ->

        $('listbox').template {
            listitem {
                listcell()
                listcell()
                listcell()
                listcell()
            }
        }

        $('paging') pageSize PAGE_SIZE totalSize Zipcode.count()

        redraw(0)

        $('paging').on('paging', {
            redraw $(it).activePage()
        })

        $('listbox').on('select', {
            def zipcode = $(it).object()
            $('gmaps') lat zipcode?.lat lng zipcode?.lng
        })
    }

    def redraw(page=0) {
        def list = Zipcode.list(offset: PAGE_SIZE * page, max: PAGE_SIZE)
        $('listbox').fill(list, 'listitem', [
            id:    'listcell:eq(0)',
            city:  'listcell:eq(1)',
            state: 'listcell:eq(2)',
            pop:   'listcell:eq(3)'
        ])
        $('listbox').selectedItem null
    }
}

Our code starts from the first line of Closure afterCompose (line 7). The listbox is selected by $('listbox') and we call .template() to define a UI template for it (line 9-16).

Then, at line 18, we select the pagination component by $('paging'), set pageSize and totalSize properties. This kind of syntax provided by Groovy since 1.8 looks really cool. But do not warry if you're not familiar with this syntax. Using property accessors also works perfectly here.

Line 19 calls redraw(0) to display the first page of data. This method retrieves a page of data from the domain class Zipcode and then “fill” them into the listbox, as selected by $('listbox'). Method fill performs UI rendering by using the template defined by line 9-16 and automatically binds each Zipcode object, from the list, to each 'listitem' component. All 4 data columns are specified by the Map parameter contains Zipcode's property names, which are id, city, state and pop, respectively (line 34-39).

Every time the render process is finished, the selected item of the listbox is set to null (line 40) to not selecting any item of the listbox.

You may find 2 UI event handlers at line 22-24 and 26-29. The first one, $('paging').on('paging'), is for handle page change. Every time the pagination component is changed, we will retrieve another set of data and re-fill to the listbox. The second one, $('listbox').on('select'), is for handling item selection. When the listbox is selected, the current Zipcode object attached to the selected listitem can be retrieved via $(it).object() and its data is used to update the Google map.

URL Mapping

Next is a cosmetic touch to make “index.zul” show up as the default page. Open 

grails-app/conf/UrlMappings.groovy

and add the following line:

"/"(view:"/index.zul")

to the static mapping = { ... } block, like this:

class UrlMappings {

    static mappings = {
        "/$controller/$action?/$id?"{
            constraints {
                // apply constraints here
            }
        }

        "/"(view:"/index.zul")
        "500"(view:'/error')
    }
}

After everything is set up. Make sure your local MongoDB instance is running and then calling:

$ grails run-app

or try an on-line one here.

Some things to note

  • I use $(...) with tag names rather than IDs to select components. This is for demonstration only. In a real application, we often define an ID to a component and use $('#id') to select it.

  • The jQuery programming model is straightforward. It's the active way of thinking. You can still do what you want actively with the more concise syntax.

  • Data-binding mechanism in ZKGrails 2.2 is greatly simplified. You can use it without using any binding annotation. Just 2 steps, define a template, and fill. (We actually use the ZK data-binding underneath anyway).

Conclusion

In this article, you've seen a quick and easy way to create a MongoDB application using ZK & Grails. This article is intended to show that you can gain a lot productivity from using Grails to develop your enterprise application, compared to Java. Combined with the power of ZKGrails , you'll find that creating a server-side AJAX application is fun and effective.

Published at DZone with permission of its author, Chanwit Kaewkasi.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)