Grails: print QRCodes with qrcode 0.3 plugin nested into rendering 0.4.3 plugin

The output app side all ways forever scared me: since building a printer output “bit by bit” with escape codes into a MS-DOS app, to make a complex print form helped by tools like Cristal reports, It’s evident for me the output is a boooring task.

But all has changed when I had discovered any of the output plugins set of grails environment: export, rendering and the fantastic qrcode. With those tools the making of a output is a easily and quickly thing.

Following the dependence injection of the Grails paradigm, We have only declare the  instance plugin into our controller and Springs make it the rest. (qrcode and rendering only have it to make the plugin installation into the project context)

But stop us the theory and go to the cake: the render of a QRCode is whatever a simply question: only we need the well installed plugins, one action which will be called from the view:

   def printFragmentosQrCode = {
             def entradaInstance = Entradas.get(params.id)         
             renderPdf(template: "/printTest",model:[Objects2QRList:entradaInstance.fragmentos,entradaInstance:entradaInstance],filename: "fragsQRCodes.pdf")
        }

and a GSP template wich has the rendering responsibility:

<%@ page contentType="text/html;charset=UTF-8" %>

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Sample title</title>
    </head>
    <body>
        <g:each in="${Objects2QRList}" var="o" >
            <qrcode:image width='o?.size' text="${o?.encodeAsHTML()}" />
        </g:each>
    </body>
</html>

If we analyze the code, It looks simple; the action take a objects collection (entradaInstance.fragmentos) and send it to the template with a name of output pdf file (also may be a png). Into template, It generate the plugin call by the insert of the specific tags, the <qrcode> tag;

<qrcode:image width="90" text="${o?.referencia.encodeAsHTML()},${o?.tipoFragmento.nombreProcesado}" />

The rendering plugin have to create a xml file and finally transform it in a pdf with a serie of png 2D codes. Unfortunately, the nesting plugins generate a xml ‘not well formed’ error with s entity:

"The reference to entity “s” must end with the ';' delimiter exception"

Googling I could see the xml error was a problem relates with the bad resolving by xml parser of the ‘&’ special character. Anyway, my problem don’t was a self code problem but was a plugin code ‘bug’ (at least a not well formed XML disfunction)

The advantage of free software let me to see the source code of qrcode plugin files. A plugin has a similar structure that whichever grails project: controller(s), view(s),  tag library(s) an more…It was easy to find the origin of my problem:

It was a ‘bug’ in the building of qrcode image url. The ‘s’ entity it’s really the size property of the image (and the size attribute of  <qrcode> tag) as I could see in the ‘QRCodeTagLib.groovy’ file:

  def image = { attrs ->
    def size = attrs.height?:attrs.width
    String text = attrs.text
    String src = createLink(controller:'qrcode',action:'text',params:[text:text,s:size])
    out << """ <img class="qrcode" src="${src}" alt="${text}" />"""
}

The src attribute of the <img> tag was valued by $src variable, wich was generated into the own closure by a call to ‘text’ action of controller (with the createLink() groovy function). Then, there was the problem.

I suppose the bug could be a bad generation of url image string, more exactly with the ‘&’ characters of the concatenation of the GET params request. Then, the solution was  replace those with the appropiate equivalence ‘&amp;’.

For this, I used the replaceAll() groovy function and the result was:

def image = { attrs ->
    def size = attrs.height?:attrs.width
    String text = attrs.text
    String src = createLink(controller:'qrcode',action:'text',params:[text:text,s:size])
     String src2=src.replaceAll(/&/,'&')
    out << """ <img class="qrcode" src="${src2}" alt="${text}" />"""
    }

Yeah! I did!

Don’t remember to modificate the others tags into tagLib plugin.

Regards squids.

Advertisements

Grails; Convert a generic projection resultSet in a JSON list of maps


A few time ago We had had to send a concrete projection (one column) from one entity’s model to the connected view in a grails web applicaton for achieve autocompleted controls in the web form.

As well as we had selected grails framework to develop the web project, We also had selected jquery to build a rich user interface. Obviously, the data exchange format between model ans view is JSON. So, our need was to convert a GORM-hibernate projection to a well formed JSON data set.

First, We have builded a Service with the goal of manage the layers communication and we had injected the converters.JSON grails plugin to facility a easy management of created JSON objects. The initial task went the creation of the solution to the more easy case: One JSON list from a unique column:

/**
    Achieve a list with all the values from a Entity's field
    Luis Torres. EBD-CSIC
    */       
    def listadoColumna={field,entity->

        def lista=entity.withCriteria{
            projections{
                distinct(field)
            }
            and
            //Hay que eliminar los nulos de la lista pq falla el autocomplete de jquery
            {isNotNull(field)}
            order(field,"asc")
        }
        def listaJSON=(lista as JSON).toString()
        return listaJSON
    }

Easy,isn’t It? Clearly, Groovy-GORM language simplify our life and help us to a easy way of code 😉

The next step went a few more complicated: How to create a “maps JSON” list from a anonymous projection? To solve this question We had thinked to send a list of separated titles and another list with the data set created by the GORM projection request like functions parameters to a closure.

    /**
    Function for iterate over a list of list and convert It to a list of maps
    Luis Torres. EBD-CSIC
    */   
    def listOfMaps2JSON(List lista,List fieldTitles){

        def tupla=[]
        lista.each(){row->
            //For each row, It define a map object
            def mapa=[:]
            row.eachWithIndex(){item,i->
                //For each item of the row, It add a value into the map object
                mapa.put(fieldTitles[i],item)                   
            }
            //Once is finished the items addition into th map, He is added to tupla list like as item
            tupla.add(mapa)
        }
        def listaJSON=tupla.encodeAsJSON()
        return listaJSON
    }

Here, the the icing on the cake is the “nested closures” solution to iterate over every list item, and put its subitems to a map who was created at every iteration. The JSON list consequence was trivial.

The elegance of Groovy solution is fantastic: only 10 codelines, brackets included, to obtain a piece of functional (and not trivial) code. I love It!

We still need a little function to send to listOfMaps2JSON the arguments:

    /**
    Achieve a list of list from all values from a Entity projection 
    defined in a list of fields
    Luis Torres. EBD-CSIC
    */       
    def listadoTuplas={fields,entity->

        def lista=entity.withCriteria{
            projections{
                fields.each{field->                  
                    property(field)                               
//                    and
//                    {isNotNull(field)}
                }               
            }
            order(fields[0],"asc")
        }   
        //Eliminate the duplicate entries of resultSet
        def lista2=lista.unique()

        return listOfMaps2JSON(lista2,fields)
    }

The Criteria is similar to listadoColumnas() criteria, but notice in this case the IsNotNull filter has been eliminated: the cause is the goal previously cited, because We should want is a “tuple” list for autocompleted webcontrols sources drawing the connection between the columns of a tuple: It belonging to the same object.

The complete Service code is:

import grails.converters.JSON

class JsHandlerService {

    /**
    Achieve a list with all the values from a Entity's field
    Luis Torres. EBD-CSIC
    */       
    def listadoColumna={field,entity->

        def lista=entity.withCriteria{
            projections{
                distinct(field)
            }
            and
            //Hay que eliminar los nulos de la lista pq falla el autocomplete de jquery
            {isNotNull(field)}
            order(field,"asc")
        }
        def listaJSON=(lista as JSON).toString()
        return listaJSON
    }

    /**
    Achieve a list of list from all values from a Entity projection 
    defined in a list of fields
    Luis Torres. EBD-CSIC
    */       
    def listadoTuplas={fields,entity->

        def lista=entity.withCriteria{
            projections{
                fields.each{field->                  
                    property(field)                               
//                    and
//                    {isNotNull(field)}
                }               
            }
            order(fields[0],"asc")
        }   
        //Eliminate the duplicate entries of resultSet
        def lista2=lista.unique()

        return listOfMaps2JSON(lista2,fields)
    }

    /**
    Function for iterate over a list of list and convert It to a list of maps
    Luis Torres. EBD-CSIC
    */   
    def listOfMaps2JSON(List lista,List fieldTitles){

        def tupla=[]
        lista.each(){row->
            //For each row, It define a map object
            def mapa=[:]
            row.eachWithIndex(){item,i->
                //For each item of the row, It add a value into the map object
                mapa.put(fieldTitles[i],item)                   
            }
            //Once is finished the items addition into th map, He is added to tupla list like as item
            tupla.add(mapa)
        }
        def listaJSON=tupla.encodeAsJSON()
        return listaJSON
    }  
}

Cheers squids!

A little bug in Grails Searchable plugin

I’m going to develop -really, I’m in analysis of requirements phase, but we need a set of web tools for managing the legacy data infrastructure- a management scientific collections project and, after try a lot of web technologies, I select Grails. Grails offer, under my point of view, multiple advantages wich promote their election:

  • A solid and maintainable infrastructure for MVC web based projects
  • A dynamic and easily learn-to language: Groovy
  • A framework IoC based
  • A natural connection and integration with legacy Java systems and Java libraries
  • A integration with ORM persistence (here, hibernate)
  • Finally, a facility for add multiple (GNU) plugins.

This last facility has been which has permitted to integrate easily a search service based of lucene engine. Lucene is a strong search engine for multiple search types: by generic match, or by substrings…over all the data or over a specific column…searching with wildcards and concatenation operators… and all over a only textbox.

The grails plugin is the searchable plugin. Once has been  installed in our grails project, the declaration in a domain groovy class makes the container inyect the Searchable class and then It can be utilized by the controller class for generate a search method.

Searchable has two first methods applied how static domain class methods (ClassSearchable.search() and ClassSearchable.searcEvery()), search and searchEvery, wich deliver a resultSearch object but at two distinct faces:

  • A paginate object
  • A full list hits object

If You wants to show a paginate list, the search first method is the ideal candidate. Else if You was thinking at a persistent memory object -like a file, the second search method is the best.

In my project, It was possible a search without a knowledge of the exact term. There, the use of wildcards  are necessary. Moreover, was intended than If the result of search It was a empty list, another suggested query could be indicated.

But I had seen that anything was not well. No suggests occurred when the find pattern contained a wildcard. The debug process indicates a null resultSearch…I don’t understander.

I tried to eliminate the suggested query indication…argg..else It ran! I googled and then I seen that It’s a plugin bug…and I think is not yet parched 😦 .

The solution is not fine: I find a null searchResult for activate the suggest query option. This is the code:

    def search = {
        try {
            def query=params.q?:flash.queryString
            params.q=flash.queryString
            if (!query) {
                flash.message="No hay parámetros. Reconstruya la consulta..."
                redirect(action:"index")
                return [:]
            }
            params.max = Math.min(params.max ? params.int('max') : 17, 100)
            //ojo a suggestQuery (param) y suggestedQuery (property)

            def searchResult = Catalogo.search(query,params)
            flash.queryString = query
            //OJO: Hasta que no se obtenga la búsqueda, no se puede generar la consulta
            //con sugerencia, porque si no peta si q lleva wildCards -es un bug del plugin-
            if(searchResult.total==0){
                params.suggestQuery = true
                searchResult = Catalogo.search(query,params)
                def sugerida = searchResult.suggestedQuery
                flash.message = sugerida
            }
            return [searchResult: searchResult, params:params]
        }
        catch (e) {
            return [searchError: true]
        }
    }

I’d like you to be useful. Regards squids!