Aman Aggarwal « Intelligrape Groovy & Grails Blogs
Subscribe via E-Mail:

Aman

http://www.IntelliGrape.com

Grails & Agile Enthusiast

Posts by Aman:

  • Server-to-server POST request

    17 Jan 2011 in Grails

    Server to server POST request can be made using Apache Commons HttpClient library.
    You need to include http-client jar file in project/lib folder and execute following lines of code:


    HttpClient client = new HttpClient()
    String url = "http://localhost:8080/test/person/delete/1"
    PostMethod method = new PostMethod(url)
    int returnCode = client.executeMethod(method) //Response Code: 200, 302, 304 etc.
    def response = method.getResponseBodyAsString() // Actual response

    Hope it helps

    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Grails annotation – Validateable

    15 Sep 2010 in Grails

    We can easily validate domain classes and command objects using static constraints. But how about validating DTOs or any groovy class in src/groovy folder.

    The answer is YES, they can be validated too. Follow two simple steps:

    1. Add annotation ‘@Validateable’ above the class.
    2. Declare the package to be validated in Config.groovy as:

    grails.validateable.packages = ['com.mycompany.dto']

    Click here to read complete documentation.

    I wish I knew this earlier. Grails rocks!!


    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Searchable plugin – Lucene search on numeric values

    14 Jul 2010 in Grails

    While using searchable plugin for the first time, I wasn’t aware that lucene implements only lexicographic comparisons for searching on indexed values (even on numeric fields). Before I learned this, I kept on wondering why a Person of age 6 always appeared in search results when I look for People more than 20 years of age. The solution was to define a transient field ageIndexValue in domain class Person and implement its getter as:

    String getAgeIndexValue() {
        return org.apache.lucene.document.NumberTools.NumberTools.longToString(this.age)
    }

    Also, you will need to change the search query from

    q=age:[20 TO *] to q=ageIndexValue:[0000000000000u TO *]
    where, 0000000000000u == org.apache.lucene.document.NumberTools.longToString(20L)

    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Grails criteria query example for unidirectional one-to-many relationships

    14 Jun 2010 in Database& Grails

    Following is an example of unidirectional one-to-many relationship:

    class Employee {
        String name
        static hasMany = [roles: Role]
    }
     
    class Role {
        String name
    }

    How can we find all the employees with a particular role – “Grails Developer”?

    Role role = Role.findByName("Grails Developer")

    One way of doing this can be:

    Employee.list().findAll{role in it.roles}

    This is an inefficient way since, we are fetching all the records from the database every time. Also, in case we are showing paginated view of results, we will need to manage pagination ourself.

    A better way of this will be using createCriteria() query:

    List<Employee> employees = Employee.createCriteria().list{
        roles{
            eq('id', role.id)
        }	
        firstResult(20)
        maxResults(20)	
    }

    I am wondering what will be the query in case Role.groovy is an enum.


    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Injecting Method to trim string length on gsp pages

    03 May 2010 in Grails& Groovy

    Restricting the length of a string on gsps is a common scenario in most of our projects.
    Groovy’s metaprogramming magic made it too simple for me. I added the following lines of code to Bootstrap.groovy:

    Object.metaClass.trimLength = {Integer stringLength ->
     
        String trimString = delegate?.toString()
        String concatenateString = "..."
        List separators = [".", " "]
     
        if (stringLength && (trimString?.length() > stringLength)) {
            trimString = trimString.substring(0, stringLength - concatenateString.length())
            String separator = separators.findAll{trimString.contains(it)}?.min{trimString.lastIndexOf(it)}
            if(separator){
                trimString = trimString.substring(0, trimString.lastIndexOf(separator))
            }
            trimString += concatenateString
        }
        return trimString
    }

    Now, for an instance of class Person:

    class Person {
        String name
     
        String toString(){
            return name
        }
    }
     
    Person person = new Person(name: "Aman Aggarwal")

    I can simply write this code in gsp:

    person.trimLength(10)

    which renders output:

    Aman...

    Hope it helps.

    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Groovy Maps: Reverse Sort

    15 Apr 2009 in Grails& Groovy

    I want to quickly share how you can sort a Map by its key/value/field of valueObject; in either ascending or descending order using Groovy

    I created a Map<String, Person> as follows:

    class Person {
        String name
        Date dateOfBirth
     
        static constraints = {
        }
    }
     
    Map <String, Person> people = [:]
    [*(11..20), *(1..10)].each {
        Person person = new Person()
        person.name = "Person-" + it
        use(org.codehaus.groovy.runtime.TimeCategory) {
            person.dateOfBirth = new Date() - (new Random().nextInt(15) + 10).years
        }
        people[person.name] = person
    }

    Now, Sorting maps in ascending order is a simple one line code:

    // Sort by Key(Person's Name):
    map = map.sort {it.key}
     
    // Sort by Value(Person Object):
    map = map.sort {it.value}
     
    // Sort by a particular field of Value(Date Of Birth):
    map = map.sort {it.value.dateOfBirth}

    But how about sorting in reverse order. It would have been great to have map.reverse() or map.reverseSort{} available in Groovy. Since none exists, I had to create the following method:

    Map reverseSortMap(Map unsortedMap) {
     
        // Different implementations of Comparator
        // 1. Reverse Sort by Key(Person's Name):
        Comparator comparator = [compare: {a , b ->
        b.compareTo(a)
        }] as Comparator
     
        // 2. Reverse Sort by Value(Person Object):
        Comparator comparator = [compare: {a , b ->
        unsortedMap.get(b).compareTo(unsortedMap.get(a))
        }] as Comparator
     
        // 3. Reverse Sort by a particular field of Value(Date Of Birth):
        Comparator comparator = [compare: {a , b ->
        unsortedMap.get(b).dateOfBirth.compareTo(unsortedMap.get(a).dateOfBirth)
        }] as Comparator
     
        Map sortedMap = new TreeMap(comparator)
        sortedMap.putAll(unsortedMap)
     
        return sortedMap
    }

    Use either of the Comparator implementations above & use the method:

    people = reverseSortMap(people)

    Hope it helps.


    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Groovy Finding Past/Future Dates

    06 Apr 2009 in Grails& Groovy

    Often I found it painful working on dates when I had to find a past/future date based on weeks, months or years.

    Groovy class org.codehaus.groovy.runtime.TimeCategory has very helpful & intutive syntax for working on dates.
    I am sure I need not to explain what each of the following statements will do:

    Date date = new Date()
     
    use(org.codehaus.groovy.runtime.TimeCategory) {
        date = date - 10.seconds
        date = date - 10.minutes
        date = date - 10.hours
        date = date - 10.days
        date = date - 10.weeks
        date = date - 10.months
        date = date - 10.years
    }


    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Groovy Collection method: groupBy()

    06 Apr 2009 in Grails& Groovy

    public Map groupBy(Closure closure)

    Going through Groovy Collection, I found this powerful method which takes a Closure as parameter & based on the closure, it returns a map in which all unique values returned by closure act as keys.

    Lets take an example:

    If you want to group integers between 1 to 100 based on the integer value at units place as follows:

    [1:[1, 11, 21, 31, 41, 51, 61, 71, 81, 91],
    2:[2, 12, 22, 32, 42, 52, 62, 72, 82, 92],
    3:[3, 13, 23, 33, 43, 53, 63, 73, 83, 93],
    4:[4, 14, 24, 34, 44, 54, 64, 74, 84, 94],
    5:[5, 15, 25, 35, 45, 55, 65, 75, 85, 95],
    6:[6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
    7:[7, 17, 27, 37, 47, 57, 67, 77, 87, 97],
    8:[8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
    9:[9, 19, 29, 39, 49, 59, 69, 79, 89, 99],
    0:[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]]

    Just think of the code you will need to write in Java for this.

    However, its a single method call in Groovy: (1..100).groupBy{it%10}

    Hope to find more such methods over time.


    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark
  • Restricting all URLs to end with .html in a Grails Application

    03 Apr 2009 in Grails& Groovy

    While going through the grails-users mailing list, I found a question about restricting all URLs to end with ‘.html’ & returning Error 404 for the default mappings. After spending some time, I was able to build a sample CRUD application restricting URLs to end with .html.

    I did the following steps for the same:

    1. Create a new grails application with name ‘Urlmapping’: grails create-app Urlmapping
    2. Create domain class Urltest: grails create-domain-class Urltest
    3. Add a String variable ‘test’ in domain class Urltest:

    class Urltest {
        String test
        static constraints = {
        }
    }

    4. Generate controllers & views for Urltest: grails generate-all Urltest
    5. Changed the UrlMappings in UrlMappings.groovy:

    class UrlMappings {
        static mappings = {
            "/$controller/$action/$id.$suffix"
            {
                constraints {
                    suffix(matches: 'html')
                }
            }
            "/$controller/$action.$suffix"
            {
                constraints {
                    suffix(matches: 'html')
                }
            }
            "/"(view: "/index")
            "500"(view: '/error')
        }
    }

    6. Removed the Entry “html: ['text/html','application/xhtml+xml'],” from map grails.mime.type in Config.groovy

    7. Created initial data in BootStrap.groovy:

    class BootStrap {
        def init = {
            servletContext - &amp; gt;
            Urltest urltest
            (1..5).each {
                urltest = new Urltest(test: 'Test-' + it)
                urltest.save()
            }
        }
        def destroy = {
        }
    }

    Run the application: grails run-app

    Now, I had to use following urls for CRUD functionality:

    # http://localhost:8080/mailing/urltest/index.html
    # http://localhost:8080/mailing/urltest/list.html
    # http://localhost:8080/mailing/urltest/create.html
    # http://localhost:8080/mailing/urltest/show/1.html
    # http://localhost:8080/mailing/urltest/edit/1.html

    (Scaffolding generated links http://localhost:8080/mailing/urltest/index, http://localhost:8080/mailing/urltest/edit/1 & http://localhost:8080/mailing/urltest/show/1 etc. won’t work since default associated UrlMapping "/$controller/$action/$id?" has been removed from UrlMappings.groovy)

    To convert the links into desired format, you needs to pass suffix=’html’ as params to g:link & g:form tags on all views & redirects in Controller.

    I have attached the source code for reference.

    This was my first attempt for editing default Url mappings. I am sure I will be able to find better & less tedious ways of doing the same over a period of time.

    Also, I would like to mention that I found broken links generated by g:paginate tag.
    A JIRA issue exists for the same.


    ~Aman Aggarwal
    aman@intelligrape.com

    http://www.IntelliGrape.com/

    • Share/Bookmark