Module配置之“Closure的利用”

传统的Module配置一般采用XML - 这种繁杂的东西就不去说它了。

随着脚本语言在Java中的引入,我们有了更简洁更易维护的Module配置方式。

subclass一个Groovy的BuilderSupport先:

package com.g
/**
 * Created by IntelliJ IDEA.
 * User: S.C.
 * Date: 5/3/11
 * Time: 9:54 AM
 * To change this template use File | Settings | File Templates.
 */

import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH

import com.g.utils.EvalUtils

class Module extends BuilderSupport {

    private static Map modules
    public static final String HOME = 'Home'

    public static Map getModuleByClazz(clazzOrClazzName) {
        for(KV in modules) {
            if((clazzOrClazzName instanceof String ? KV.value.clazz?.name : KV.value.clazz) == clazzOrClazzName) {
                return KV.value    
            }    
        }    
    }
    public static String getBelongsToFieldName(m) {
        def belongsTo = m?.belongsTo
        if(!belongsTo) return null
        def fieldName = belongsTo.name.split('\\.')[-1]
        fieldName[0].toLowerCase() + fieldName[1..-1]
    }

    protected void setParent(Object parent, Object child){
        if(parent.children == null) parent.children = []
        parent.children << child
        child.parent = parent
    }
    protected Object createNode(Object name){
        createNode(name, null)
    }
    protected Object createNode(Object name, Object value){
        createNode(name, null, value)
    }
    protected Object createNode(Object name, Map attributes){
        createNode(name, attributes, null)
    }
    protected Object createNode(Object name, Map attributes, Object value){
        def module = attributes ?: [:]
        module.name = name
        module.id   = name.encodeAsMD5()
        module.label = module.label ?: (module.clazz ? null : module.name)
        module.description = module.description ?: module.qtip ?: module.label
        modules[name] = modules[module.id] = module
        return module
    }
    protected void nodeCompleted(Object parent, Object node) {
        if(node.clazz && !node.belongsTo) {
            def p = parent
            while(p && !p.clazz) {
                p = p.parent
            }
            node.belongsTo = p?.clazz
        }
    }

    def invokeMethod(String name, args) {
        try{
            super.invokeMethod name, args
        }catch(x){
            println x
        }
    }

    private static void build() {
        println "building modules ..."
        modules = [:]
        def file = new File(SCH.getServletContext().getRealPath("/WEB-INF/db/modules.groovy"))
        if(file.exists()) {
            def b = new Module()
            def c = EvalUtils.eval('{->'+file.text+'}')
            b."$HOME"(c)
            println "built ${modules.keySet().size()/2} modules."
        }
    }

}

module.groovy配置文件:

Sponsors {
    Sponsor(
    label: {o->o.name},
        description:{o->"${o.name}<br>${o.address?.country?:''}"},
        searchFields:'name',
        qtip: {o->"<table><tr><td align='right'><b>Name:&nbsp;<b></td><td>${o.name}</td></tr></table>"},
        sort: 'name', clazz: Sponsor, idRex:{usr->
        User.isInternalAccount(usr) ? '.*' : ''
        }, defaultInternalPermission:'ru'
    )
}
Studies {
    Study(
    label: {o->"${o.jobCode}${o.nickname?(' : '+o.nickname):''} (Sponsored by ${o.sponsor?.name})"}, plural:'Studies',
        description:{o->
            def desc = ["<b>${o.jobCode}</b><br><br><table>"]
            desc << "<tr><td><b>Sites in total:</b>&nbsp;&nbsp;&nbsp;&nbsp;</td><td align='right'>${Site.findAll(study:o).size()}</td></tr>"
            GenericSelectionItem.findAll(sort:'name', group:'siteStatus').each{status->
              desc << "<tr><td><b>${status.html}:</b>&nbsp;&nbsp;&nbsp;&nbsp;</td><td align='right' width='500'>${Site.findAll(study:o, status:status).size()}</td></tr>"
            }
            def subjects = Subject.findAll('site.study':o)
            desc <<"<tr><td>&nbsp;</td><td>&nbsp;</td></tr>"
            desc << "<tr><td><b>Subjects in total:</b>&nbsp;&nbsp;&nbsp;&nbsp;</td><td align='right'>${subjects.size()} (<font color='red'><b>${Subject.findAll('site.study':o, screenFailure:true).size()} Screen Failures</b></font>)</td></tr>"
            desc << "</table>"
            desc.join()
        },
        searchFields:'jobCode,nickname',
        qtip: {o->
           """<table>
           <tr><td><b>JobCode:</b>&nbsp;&nbsp;&nbsp;&nbsp;</td><td>${o.jobCode}</td></tr>
           <tr><td><b>Nickname:&nbsp;&nbsp;&nbsp;&nbsp;</td><td>${o.nickname?:''}</td></tr>
           <tr><td><b>Sponsor:&nbsp;&nbsp;&nbsp;&nbsp;</td><td>${o.sponsor?.name?:''}</td></tr>
           </table>"""
        },
        sort: 'jobCode', clazz: Study, idRex: {usr->
        def accessibleStudies = ACL.findAll(module:'Study', users:usr)?.oid.join('|')
            def ownedStudies = Study.findAll(all:true,version:0,createdBy:usr?.username)?.id.collect{it.substring(0,36)}.join('|')
            return accessibleStudies+'|'+ownedStudies
        }
    ) {
        // ...
    "Euro Country Specific Documents"(hide:{mid->
    !Study.isEuro(mid.split(':')[1]) 
})   {
            //...
        }
    }
}
System {
    // ...
}
Help {
    // ...
}
 

 Module配置文件(groovy)中大量使用了Closures,其中一个最简单的例子是

"Euro Country Specific Documents"(hide:{mid->
     !Study.isEuro(mid.split(':')[1])
})
 

这样在显示modules的时候,这个hide closure将被调用,专门为涉及Euro Countries的Study做的Module "Euro Country Specific Documents"就能智能地根据某一指定的study(临床试验项目)是否在欧洲国家做来显示/隐藏,酱紫管module显示的代码就可以做的很简洁,无他,唯调用closure而已:

// ...
if(m.hide?.call(params.id)) {
    continue        
}
// ...
 

---------- P.S. Study#isEuro ----------

public static boolean isEuro(sid) {
    // The countries currently using the euro are:
    // 1) Andorra
    // 2) Austria
    // 3) Belgium
    // 4) Cyprus
    // 5) Estonia
    // 6) Finland
    // 7) France
    // 8) Germany
    // 9) Greece
    // 10) Ireland
    // 11) Italy
    // 12) Kosovo
    // 13) Luxembourg
    // 14) Malta
    // 15) Monaco
    // 16) Montenegro
    // 17) Netherlands
    // 18) Portugal
    // 19) San Marino
    // 20) Slovakia
    // 21) Slovenia
    // 22) Spain
    // 23) Vatican City
    def euroCountries = Country.findAll(name:~/Andorra|Austria|Belgium|Cyprus|Estonia|Finland|France|Germany|Greece|Ireland|Italy|Kosovo|Luxembourg|Malta|Monaco|Montenegro|Netherlands|Netherlands Antilles|Portugal|San Marino|Slovakia|Slovenia|Spain|Holy See \(Vatican City\)/)
    !!Study.find(id:sid){
        def qq = it.descend('countries'), c
        euroCountries.each{
            def c1 = qq.constrain(it)
            c = c ? c.or(c1) : c1        
        }
    }
}
 

猜你喜欢

转载自sam-ds-chen.iteye.com/blog/1113835
今日推荐