Nested set plugin for Grails

We are happy to announce that our NestedSet plugin for the Grails framework has been released. The plugin creates a hierarchical structure on top of plain database records. A description of the “nested set” data structure can be found in Wikipedia.

The NestedSet Grails plugin is

  • non-intrusive – it does not change your data model, just adds one table
  • easy to use – just add “static nestedSet = true” to the domain class
  • versatile – it supports multiple hierarchies

Installation instructions and usage details can be found at the NestedSet plugin homepage.

If you find it useful, tell your friends. If there is a problem, please register at grails.cz and create a new issue.

Playing with Grails application configuration

This small tutorial will show how to create a configuration file and how to manage configuration of your Grails application. It will show how to

  • Access configuration parameters
  • Create external configuration
  • Configure Spring for different environments
  • Create a new environment

Accessing configuration parameters

The configuration of Grails is stored in grails-app/conf directory. Parameters are stored in configuration files in “plain text way”

app.default.user = "tester"

or in “structured way”

app{
	default{
		user = "tester"
	}
}

In an application, one can access the parameters easily. Just import the correct class and ask it the correct question.

import org.codehaus.groovy.grails.commons.ConfigurationHolder
 
class TestController {
	def query = {
		render ConfigurationHolder.config.app.default.user
	}
}

The example above should render the string “tester”. Moreover, in the configuration files, one can easily define distinct config values for each of three different environments – production, development and test.

environments {
	production {
		grails.serverURL = "http://www.changeme.com"
	}
	development {
		grails.serverURL = "http://www.do-not-change.cz"
	}
	test {
		grails.serverURL = "http://www.just-for-test.de"
	}
}

External configuration

The configuration mechanism of Grails is nice, but there is a small trouble. The configuration files are compiled and packed into the deployment package (WAR) during project build phase. However, one usually does not want to rebuild the whole application just to change say a database password. So, how to do it?

The first step is to create an external configuration file. Let’s name it externalConfig.groovy. Its structure will be the same as the structure of the other configuration files – “flat text” or “structured”.

Now, how do you tell Grails to find and use it? Adding the following code to the beginning of your config.groovy will do the trick. It expects that there is an OS environment variable MY_GREAT_CONFIG that points to the configuration file.

if(System.getenv("MY_GREAT_CONFIG")) {
	println( "Including configuration file: " + System.getenv("MY_GREAT_CONFIG"));
	grails.config.locations << "file:" + System.getenv("MY_GREAT_CONFIG")
} else {
	println "No external configuration file defined."
}

Spring configuration

The grails-app/conf/spring/resources.groovy file gives the developer a convenient way to define beans. Distinguishing environments is slightly more complex than in other configuration files, but still elegant.

switch(GrailsUtil.environment) {
	case "production":
		myBean(package.BeanClass, 1, "prod")
		break
	case "test":
		myBean(package.BeanClass, 1, "test")
		break
	case "development":
		myBean(package.BeanClass, 1, "dev")
		break

Configuration parameters can be used here the same way as in the controller example above.

myBean(package.BeanClass, 1, ConfigurationHolder.config.app.default.user)

Adding more environments

It might seem that the development, test and production environments are just enough. Yes, that is true for most basic scenarios. However, if you develop for a large company with sophisticated deployment procedures, there are typically several production-level application server environments (one for user acceptance testing, one for system patch analysis and performance testing, one for production etc.), all of them corresponding to the Grails “production” environment.

How to address this scenario? Easily. Just introduce another environment into your configuration

environments {
	production {
		grails.serverURL = "http://www.changeme.com"
	}
	development {
		grails.serverURL = "http://www.do-not-change.cz"
	}
	test {
		grails.serverURL = "http://www.just-for-test.cz"
	}
	uat {
		grails.serverURL = "http://www.uat-testing-environment.cz"
	}
}

and run the application or create a war file with an extra parameter

	grails -Dgrails.env=uat war
	or
	grails -Dgrails.env=uat run-app

Configuration and usage of Gldapo in a Grails project

Configuration and usage of Gldapo in a Grails project

Gldapo is a groovy library for object oriented LDAP access. “The Gldapo is to LDAP what GORM is to SQL”.

Gldapo is packaged in Grails LDAP plugin, its installation is easy. In the root of your Grails project run command:

grails install-plugin ldap

Configuration

The Gldapo is configured in the Config.groovy file. Here follows an example.

ldap {
    directories {
        user { 
            url = "ldap://ldap.zmok.net"
            base = "OU=Users,DC=zmok,DC=net"
            userDn = "CN=usernameToLogToLdap,OU=Users,DC=zmok,DC=net"
            password = "passwordToLogToLdap" 
            searchControls { 
                countLimit = 40 
                timeLimit = 600 
                searchScope = "subtree" 
            }
        }
        group { 
            url = "ldap://ldap.zmok.net"
            base = "OU=Groups,DC=zmok,DC=net"
            userDn = "CN=usernameToLogToLdap,OU=Users,DC=zmok,DC=net"
            password = "passwordToLogToLdap"
            searchControls { 
                countLimit = 40 
                timeLimit = 600 
                searchScope = "subtree" 
            }
        }
    }
 
    schemas = [ 
        net.zmok.ldap.User,
        net.zmok.ldap.Group
    ]
 
}

The configuration is self-explaining, except of the schemas part. This is where the magic starts. The classes are object representation of the LDAP entities. So, let’s look how the classes are defined.

package net.zmok.ldap
import gldapo.schema.annotation.GldapoNamingAttribute
 
class User{
	@GldapoNamingAttribute
	String cn
	String title
	String displayName
	Set memberOf
}
package net.zmok.ldap
import gldapo.schema.annotation.GldapoNamingAttribute
 
class Group{
	@GldapoNamingAttribute
	String cn
	Set members
	@GldapoSynonymFor("mgr")
	String manager
}

Here, @GldapoNamingAttribute is mandatory and defines the key of the entity. The @GldapoSynonymFor redefines the LDAP names to human-readable format. In our case mgr will be translated to manager.

Manipulation

Usually, one needs to find a few records in an LDAP directory and do something with them. Lets say we need to find members of groups named like “Groovy*” (means GroovyProgrammers, GroovyFans, GroovyHaters) and their managers.
The Gldapo offers findAll method similar to GORM. So, here is the code to list them:

Group.findAll( directory: "group", filter: "(cn=Groovy*)" ).each{ group ->
	def groupName = group.cn
	group.members.each{ member ->
		def user = User.find( directory:"user", filter:"(cn=${member})")
		println "User ${user.displayName} managed by ${group.manager} is member of ${groupName}."
	}
}

Pretty easy, isn’t it? The User and Group classes are similar to GORM classes, so one can create, update, move, replace, delete… and much more. For details see http://http://gldapo.codehaus.org/schemaclasses/entries.html.

Grails RichUI - Incorrect international characters of the month names

I am working on a small project and I decided to use RichUI plugin do display a timeline.
The plugin is just great and working like a charm. If you want to try it, this tutorial is a very good one.

The english version works perfectly, but I have found a small bug in the czech localization. The czech characters were displayed incorrectly.
The whole page, including data of the timeline, was using utf-8 encoding (it was specified in the heading of the page), but the names of the months were in cp1250.

The problem lays in the source code of the RichUI plugin (I guess). A file with the czech names of the months was saved as cp1250 file, not as a utf-8 file.
So, the solution is simple. Change character set of the localization file

to utf-8 and save it.

Do not forget to delete

Update: The bug has been fixed in version 0.6. See Jira.

String similarity detection

I was looking for a simple string similarity detection algorithm and I did find the one on CatalySoft. Since I like it and I found it useful, I did create a groovy equivalent of it.

Here is the code:

public class LetterPairSimilarity {
 
  /** @return an array of adjacent letter pairs contained in the input string */
  private static def letterPairs(String str) {
    (0..str.size()-2).collect{str[it,it+1]} 
  }
 
  /** @return an ArrayList of 2-character Strings. */
  private static def wordLetterPairs(String str) {
    (str.split("\\s").collect{it} - [""]).collect{ letterPairs(it) }.flatten()
  }
 
  /** @return lexical similarity value in the range [0,1] */
  public static double compareStrings(String str1, String str2) {
    if (!str1 || !str2 || str1=="" || str2=="") {return 0.0}
    def p1=wordLetterPairs(str1.toUpperCase())
    def p2=wordLetterPairs(str2.toUpperCase())
 
    2*p1.intersect(p2).size() / (p1+p2).size
  }
}