Distributing Plugins in Grails Plugins Repository

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Distributing Plugins in Grails Plugins Repository

Mathieu Perez
Hello,

I would like to provide a plugin which integrates Hibernate Search with Grails in very few steps.
My Xircles username is mathpere.


1) Install the plugin


2) Define domain classes to index by adding a static search property:

class MyDomainClass {

    String author
    String body
    Date publishedDate
    String summary
    String title
    Status status

    enum Status {
        DISABLED, PENDING, ENABLED
    }

    static hasMany = [categories: Category]

    static search = {
        author index: 'tokenized'
        body index: 'tokenized'
        publishedDate date: 'day'
        summary index: 'tokenized'
        title index: 'tokenized'
        status index: 'un_tokenized'
        categories indexEmbedded: true
    }

}


3) For all indexed domain class, the plugin adds a dynamic method : .search() and provides its own query DSL wrapping the Hibernate Search query DSL.


class SomeController {

def myAction = { MyCommand command ->

def page = [max: Math.min(params.max ? params.int('max') : 10, 50), offset: params.offset ? params.int('offset') : 0]

def 
myDomainClasses = MyDomainClass.search() {

    if ( command.dateTo ) {
        below "publishedDate", command.dateTo
    }

    if ( command.dateFrom ) {
        above "publishedDate", command.dateFrom
    }

    mustNot {
        keyword "status", Status.DISABLED
    }

    if ( command.keyword ) {
        should {
            command.keyword.tokenize().each { keyword ->

                def wild = keyword.toLowerCase() + '*'

                wildcard "author", wild
                wildcard "body", wild
                wildcard "summary", wild
                wildcard "title", wild
                wildcard "categories.name", wild
            }
        }
    }

    sort "publishedDate", "asc"

    maxResults page.max

    offset page.offset

}

[myDomainClasses: myDomainClasses]
}

}

Best regards,

Mathieu

Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

burtbeckwith
Cool stuff. There's a very old Hibernate Search plugin that's abandoned - http://grails.org/plugin/hibernate-search - it'd be best to take over that project and replace the code with yours. That way there's no ambiguity about which one to use.

Does Hibernate Search get around the problem in Compass/Searchable where there's just the single non-distributed Lucene index? Or do you still need Solr or another server-based approach once you have more than one server?

Burt

> Hello,
>
> I would like to provide a plugin which integrates Hibernate Search with
> Grails in very few steps.
> My Xircles username is mathpere.
>
>
> *1) Install the plugin*
>
>
> *2) Define domain classes to index by adding a static search property:*
>
> class MyDomainClass {
>
>     String author
>     String body
>     Date publishedDate
>     String summary
>     String title
>     Status status
>
>     enum Status {
>         DISABLED, PENDING, ENABLED
>     }
>
>     static hasMany = [categories: Category]
>
>     static search = {
>         author index: 'tokenized'
>         body index: 'tokenized'
>         publishedDate date: 'day'
>         summary index: 'tokenized'
>         title index: 'tokenized'
>         status index: 'un_tokenized'
>         categories indexEmbedded: true
>     }
>
> }
>
>
> *3) For all indexed domain class, the plugin adds a dynamic method :
> .search() and** provides its own query DSL wrapping the Hibernate Search
> query DSL.*
>
>
> class SomeController {
>
> def myAction = { MyCommand command ->
>
> def page = [max: Math.min(params.max ? params.int('max') : 10, 50), offset:
> params.offset ? params.int('offset') : 0]
>
>
> def
> myDomainClasses = *MyDomainClass.search() {*
>
>
>     if ( command.dateTo ) {
>
>        * below "publishedDate", command.dateTo*
>
>     }
>
>
>     if ( command.dateFrom ) {
>
>         *above "publishedDate", command.dateFrom*
>
>     }
>
>
>    * mustNot {*
>
> *        keyword "status", Status.DISABLED*
>
> *    }*
>
>
>     if ( command.keyword ) {
>
>        * should {*
>
> *            command.keyword.tokenize().each { keyword ->*
>
> *
> *
>
> *                def wild = keyword.toLowerCase() + '*'*
>
> *
> *
>
> *                wildcard "author", wild*
>
> *                wildcard "body", wild*
>
> *                wildcard "summary", wild*
>
> *                wildcard "title", wild*
>
> *                wildcard "categories.name", wild*
>
> *            }*
>
> *        }*
>
>     }
>
>
> *    sort "publishedDate", "asc"*
>
>
> *    maxResults page.max*
>
>
> *    offset page.offset*
>
>
> }
>
>
> [myDomainClasses: myDomainClasses]
>
> }
>
>
> }
>
> Best regards,
>
> Mathieu
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

Mathieu Perez
Thanks for your answer. I studied the current version of the plugin and I think too it'd be best to replace it. 

For the index distribution, Hibernate search relies on Infinityspan

Mathieu


On Mon, Oct 31, 2011 at 12:19, Burt Beckwith <[hidden email]> wrote:
Cool stuff. There's a very old Hibernate Search plugin that's abandoned - http://grails.org/plugin/hibernate-search - it'd be best to take over that project and replace the code with yours. That way there's no ambiguity about which one to use.

Does Hibernate Search get around the problem in Compass/Searchable where there's just the single non-distributed Lucene index? Or do you still need Solr or another server-based approach once you have more than one server?

Burt

> Hello,
>
> I would like to provide a plugin which integrates Hibernate Search with
> Grails in very few steps.
> My Xircles username is mathpere.
>
>
> *1) Install the plugin*
>
>
> *2) Define domain classes to index by adding a static search property:*
>
> class MyDomainClass {
>
>     String author
>     String body
>     Date publishedDate
>     String summary
>     String title
>     Status status
>
>     enum Status {
>         DISABLED, PENDING, ENABLED
>     }
>
>     static hasMany = [categories: Category]
>
>     static search = {
>         author index: 'tokenized'
>         body index: 'tokenized'
>         publishedDate date: 'day'
>         summary index: 'tokenized'
>         title index: 'tokenized'
>         status index: 'un_tokenized'
>         categories indexEmbedded: true
>     }
>
> }
>
>
> *3) For all indexed domain class, the plugin adds a dynamic method :
> .search() and** provides its own query DSL wrapping the Hibernate Search
> query DSL.*
>
>
> class SomeController {
>
> def myAction = { MyCommand command ->
>
> def page = [max: Math.min(params.max ? params.int('max') : 10, 50), offset:
> params.offset ? params.int('offset') : 0]
>
>
> def
> myDomainClasses = *MyDomainClass.search() {*
>
>
>     if ( command.dateTo ) {
>
>        * below "publishedDate", command.dateTo*
>
>     }
>
>
>     if ( command.dateFrom ) {
>
>         *above "publishedDate", command.dateFrom*
>
>     }
>
>
>    * mustNot {*
>
> *        keyword "status", Status.DISABLED*
>
> *    }*
>
>
>     if ( command.keyword ) {
>
>        * should {*
>
> *            command.keyword.tokenize().each { keyword ->*
>
> *
> *
>
> *                def wild = keyword.toLowerCase() + '*'*
>
> *
> *
>
> *                wildcard "author", wild*
>
> *                wildcard "body", wild*
>
> *                wildcard "summary", wild*
>
> *                wildcard "title", wild*
>
> *                wildcard "categories.name", wild*
>
> *            }*
>
> *        }*
>
>     }
>
>
> *    sort "publishedDate", "asc"*
>
>
> *    maxResults page.max*
>
>
> *    offset page.offset*
>
>
> }
>
>
> [myDomainClasses: myDomainClasses]
>
> }
>
>
> }
>
> Best regards,
>
> Mathieu
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email



Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

Graeme Rocher
Administrator
In reply to this post by Mathieu Perez
Approved. Great work!

Cheers

On Mon, Oct 31, 2011 at 11:19 AM, Mathieu Perez <[hidden email]> wrote:

> Hello,
> I would like to provide a plugin which integrates Hibernate Search with
> Grails in very few steps.
> My Xircles username is mathpere.
>
> 1) Install the plugin
>
> 2) Define domain classes to index by adding a static search property:
> class MyDomainClass {
>     String author
>     String body
>     Date publishedDate
>     String summary
>     String title
>     Status status
>     enum Status {
>         DISABLED, PENDING, ENABLED
>     }
>     static hasMany = [categories: Category]
>     static search = {
>         author index: 'tokenized'
>         body index: 'tokenized'
>         publishedDate date: 'day'
>         summary index: 'tokenized'
>         title index: 'tokenized'
>         status index: 'un_tokenized'
>         categories indexEmbedded: true
>     }
> }
>
> 3) For all indexed domain class, the plugin adds a dynamic method
> : .search() and provides its own query DSL wrapping the Hibernate Search
> query DSL.
>
> class SomeController {
>
> def myAction = { MyCommand command ->
>
> def page = [max: Math.min(params.max ? params.int('max') : 10, 50), offset:
> params.offset ? params.int('offset') : 0]
>
> def
> myDomainClasses = MyDomainClass.search() {
>
>     if ( command.dateTo ) {
>
>         below "publishedDate", command.dateTo
>
>     }
>
>     if ( command.dateFrom ) {
>
>         above "publishedDate", command.dateFrom
>
>     }
>
>     mustNot {
>
>         keyword "status", Status.DISABLED
>
>     }
>
>     if ( command.keyword ) {
>
>         should {
>
>             command.keyword.tokenize().each { keyword ->
>
>                 def wild = keyword.toLowerCase() + '*'
>
>                 wildcard "author", wild
>
>                 wildcard "body", wild
>
>                 wildcard "summary", wild
>
>                 wildcard "title", wild
>
>                 wildcard "categories.name", wild
>
>             }
>
>         }
>
>     }
>
>     sort "publishedDate", "asc"
>
>     maxResults page.max
>
>     offset page.offset
>
> }
>
> [myDomainClasses: myDomainClasses]
>
> }
>
> }
>
> Best regards,
> Mathieu
>
>



--
Graeme Rocher
Grails Project Lead
SpringSource - A Division of VMware
http://www.springsource.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

pledbrook
In reply to this post by Mathieu Perez
> Thanks for your answer. I studied the current version of the plugin and I
> think too it'd be best to replace it.
> For the index distribution, Hibernate search relies on Infinityspan
> Here is the documentation:
> http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#infinispan-directories.

Does your plugin require Grails 2.0? The plugin portal is indicating yes:

    http://grails.org/plugin/hibernate-search

Peter

--
Peter Ledbrook
Grails Advocate
SpringSource - A Division of VMware

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

Mathieu Perez
We based our developments on Grails 2.0.

Actually, the only requirement relies on AbstractStaticPersistentMethod. (e.g. the interface is different between 2.0.0.M2 and 2.0.0.RC1). Do you have any suggestion?


On Thu, Nov 3, 2011 at 10:46, Peter Ledbrook <[hidden email]> wrote:
> Thanks for your answer. I studied the current version of the plugin and I
> think too it'd be best to replace it.
> For the index distribution, Hibernate search relies on Infinityspan
> Here is the documentation:
> http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#infinispan-directories.

Does your plugin require Grails 2.0? The plugin portal is indicating yes:

   http://grails.org/plugin/hibernate-search

Peter

--
Peter Ledbrook
Grails Advocate
SpringSource - A Division of VMware

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email



Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

Graeme Rocher
Administrator
It doesn't seem that the code needs to subclass
AbstractStaticPersistentMethod. You could just as easily do this:

      def sessionFactory = ctx.getBean("sessionFactory")
      def hibernateTemplate = new HibernateTemplate(sessionFactory)
      ....
      grailsClass.metaClass.static.search = { Closure closure ->
         hibernateTemplate.execute( {
                new HibernateSearchQueryBuilder(grailsClass,
session).list(closure)
        } as HibernateCallback)
      }


This way you could support earlier versions of Grails

Good job btw.

On Thu, Nov 3, 2011 at 11:58 AM, Mathieu Perez <[hidden email]> wrote:

> We based our developments on Grails 2.0.
> Actually, the only requirement relies on AbstractStaticPersistentMethod.
> (e.g. the interface is different between 2.0.0.M2 and 2.0.0.RC1). Do you
> have any suggestion?
>
> On Thu, Nov 3, 2011 at 10:46, Peter Ledbrook <[hidden email]> wrote:
>>
>> > Thanks for your answer. I studied the current version of the plugin and
>> > I
>> > think too it'd be best to replace it.
>> > For the index distribution, Hibernate search relies on Infinityspan
>> > Here is the documentation:
>> >
>> > http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#infinispan-directories.
>>
>> Does your plugin require Grails 2.0? The plugin portal is indicating yes:
>>
>>    http://grails.org/plugin/hibernate-search
>>
>> Peter
>>
>> --
>> Peter Ledbrook
>> Grails Advocate
>> SpringSource - A Division of VMware
>>
>> ---------------------------------------------------------------------
>> To unsubscribe from this list, please visit:
>>
>>    http://xircles.codehaus.org/manage_email
>>
>>
>
>



--
Graeme Rocher
Grails Project Lead
SpringSource - A Division of VMware
http://www.springsource.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Distributing Plugins in Grails Plugins Repository

Mathieu Perez
Perfect, and in addition, it improves readability.

But I met another constraint: I need to override the default session factory provided by the Grails Hibernate plugin in order to customize Hibernate configuration.

I provide my own SessionFactory bean by extending org.codehaus.groovy.grails.orm.hibernate.ConfigurableLocalSessionFactoryBean. In this way, I can override postProcessConfiguration(org.hibernate.cfg.Configuration config) method to add some Hibernate Search specific properties.

This differs between Grails 1.3.7 and 2.0. e.g.: Since Grails 2.0, we just need to refer to other bean:

    def doWithSpring = {
        sessionFactory(SearchMappingConfigurableLocalSessionFactoryBean) { bean ->
            bean.parent = 'abstractSessionFactoryBeanConfig'
        }
    }


It's far from perfect: the plugin doesn't handle multiple datasource and depends really on Hibernate plugin. 
Is there a cleaner way to customize Hibernate configuration which would be compatible between Grails 1.3.7 and 2.0? I didn't find any other way to intercept postProcessConfiguration.




On Fri, Nov 4, 2011 at 17:41, Graeme Rocher <[hidden email]> wrote:
It doesn't seem that the code needs to subclass
AbstractStaticPersistentMethod. You could just as easily do this:

     def sessionFactory = ctx.getBean("sessionFactory")
     def hibernateTemplate = new HibernateTemplate(sessionFactory)
     ....
     grailsClass.metaClass.static.search = { Closure closure ->
        hibernateTemplate.execute( {
               new HibernateSearchQueryBuilder(grailsClass,
session).list(closure)
       } as HibernateCallback)
     }


This way you could support earlier versions of Grails

Good job btw.

On Thu, Nov 3, 2011 at 11:58 AM, Mathieu Perez <[hidden email]> wrote:
> We based our developments on Grails 2.0.
> Actually, the only requirement relies on AbstractStaticPersistentMethod.
> (e.g. the interface is different between 2.0.0.M2 and 2.0.0.RC1). Do you
> have any suggestion?
>
> On Thu, Nov 3, 2011 at 10:46, Peter Ledbrook <[hidden email]> wrote:
>>
>> > Thanks for your answer. I studied the current version of the plugin and
>> > I
>> > think too it'd be best to replace it.
>> > For the index distribution, Hibernate search relies on Infinityspan
>> > Here is the documentation:
>> >
>> > http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#infinispan-directories.
>>
>> Does your plugin require Grails 2.0? The plugin portal is indicating yes:
>>
>>    http://grails.org/plugin/hibernate-search
>>
>> Peter
>>
>> --
>> Peter Ledbrook
>> Grails Advocate
>> SpringSource - A Division of VMware
>>
>> ---------------------------------------------------------------------
>> To unsubscribe from this list, please visit:
>>
>>    http://xircles.codehaus.org/manage_email
>>
>>
>
>



--
Graeme Rocher
Grails Project Lead
SpringSource - A Division of VMware
http://www.springsource.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email