使用Groovy解析OFBiz的entitymodel.xml文件之后传

在前面的文章中,讲到了如何利用Groovy操作XML,来解析OFBiz项目的实体模型文件entitymodel.xml。 本文是上一篇文章的后续,重点是如何将数据模型导出到Word文件中,支持多个模块文件,并且利用Java5的多线程机制“生产者-消费者”模式,优化了文档打印部分,使得一个模块导出一个Doc文件。 源码如下:

/**
 * ===================================================
 * Author: rain(http://rainboyan.com)
 *
 * v5 2008/12/12 14:29
 *   - 性能优化。多线程实现,文件搜索和打印输出
 *   - 支持多文件搜索路径
 *   - 重构代码
 *
 * v4 2008/12/12 9:49
 *   - 支持多模块entitydef,各个模块分别保存
 *   - 导出Word文档自动保存在用户目录下,
 *     文件命名:ofbiz-entitymodel-[module].doc
 *
 * v3 2008/12/12 9:03
 *   - 实现打印至Word文档
 *   - 增加用时统计
 *
 * v2 2008/12/12 1:16
 *   - 重构代码
 *   - 增加类:Entity和Field
 *
 * v1 2008/12/11 23:13
 *   - 实现了解析entitymodel.xml,打印至控制台。
 *   - 字段包括:
 *        Entity Name | Field Name | Field Type | PK | FK
 * ===================================================
 */
import org.codehaus.groovy.scriptom.*
import java.util.concurrent.*

static final N_MODULES = 4
static final N_THREADS = N_MODULES + 1
static final File POISON = new File("")

static final True = 1
static final False = 0

static final wdStyleHeading1 = -2
static final wdStyleHeading2 = -3
static final wdStyleHeading3 = -4
static final wdStyleHeading4 = -5
static final wdStyleHeading5 = -6
static final wdStyleHeading6 = -7
static final wdStyleBodyText = -67

static final wdTexture10Percent = 100
static final wdTexture20Percent = 200
static final wdTexture12Pt5Percent = 125
static final wdTexture15Percent = 150
static final wdTexture17Pt5Percent = 175
static final wdTexture22Pt5Percent = 225

static final wdAlignRowLeft = 0
static final wdAlignRowCenter = 1
static final wdAlignRowRight = 2

static final wdAlignVerticalTop = 0
static final wdAlignVerticalCenter = 1
static final wdAlignVerticalJustify = 2
static final wdAlignVerticalBottom = 3

static final wdLineBreak = 6
static final wdPageBreak = 7

static final wdBulletGallery = 1
static final wdNumberGallery = 2
static final wdOutlineNumberGallery = 3

static final wdListNumberStyleArabic = 0

static final wdDoNotSaveChanges = 0
static final wdSaveChanges = -1 
static final wdPromptToSaveChanges = -2


class Entity {
    String name
    String title
    List attrs = []
}
class Attribute {
    String name
    String domain
    Boolean isPK
    Boolean isFK
}

def crawl = { roots, fileFilter, fileQueue ->
    roots.each { root ->
        root.eachFileRecurse { entry ->
            if(entry.isFile() && entry.name.endsWith("entitymodel.xml")) {
	        fileQueue.put(entry)
            }
        }
    }
}
def fileCrawler = { fileQueue, fileFilter, root ->

    try {
        crawl(root, fileFilter, fileQueue)
    } catch(InterruptedException e) { /* fail */ }
    finally {
        while (true) {
	    try {
	        fileQueue.put(POISON)
	        println "Put POISON"
	        break
	    } catch (InterruptedException e1) { /* try again */ }
        }
    }

}

def getPKs = { pkeys ->
    def pks = []
    for (key in pkeys) {
        pks << key["@field"]
    }
    return pks
}

def isPK = { field, pks ->
    for (pk in pks) {
        if (field == pk) return true
    }
    return false
}
def getFKs = { relations ->
    def fks = []
    relations.each { relation ->
        def keys = relation.'key-map'
        fks << keys[0]["@field-name"]
    }
    return fks
}
def isFK = { field, fks ->
    for (key in fks) {
        if (field == key) return true
    }
    return false
}

def printEntity = { doc, entity ->
    def range = doc.Range()
    range.SetRange(doc.Range().End, doc.Range().End)
    range.Style = wdStyleHeading3
    range.InsertAfter(entity.name)

    range.InsertParagraphAfter()

    range.SetRange(doc.Range().End, doc.Range().End)
    range.Style = wdStyleBodyText
    def table = doc.Tables.Add(range, entity.attrs.size() + 2, 6)

    def row = table.Rows(1)
    row.Cells.Height = 30
    row.Cells.Shading.Texture = wdTexture20Percent
    row.Alignment = wdAlignRowCenter
    row.Cells.VerticalAlignment = wdAlignVerticalCenter
    row.range.Style = wdStyleBodyText
    row.Range.Bold = True
    row.Cells(1).Range.InsertAfter "ENTITY NAME"
    row.Cells(2).Range.InsertAfter "ATTRIBUTE NAME"
    row.Cells(3).Range.InsertAfter "CHINESE"
    row.Cells(4).Range.InsertAfter "PK?"
    row.Cells(5).Range.InsertAfter "FK?"
    row.Cells(6).Range.InsertAfter "DOMAIN"

    row = table.Rows(2)
    row.Cells(1).Range.InsertAfter entity.name
    row.Cells(6).Range.InsertAfter entity.title

    for (int i = 1; i < entity.attrs.size() + 1; i++) {
        row = table.Rows(i+2)
        row.Cells(1).Range.InsertAfter i.toString()
        row.Cells(2).Range.InsertAfter entity.attrs[i-1].name
        row.Cells(4).Range.InsertAfter entity.attrs[i-1].isPK ? "Y" : "N"
        row.Cells(5).Range.InsertAfter entity.attrs[i-1].isFK ? "Y" : "N"
        row.Cells(6).Range.InsertAfter entity.attrs[i-1].domain
    }
}

def printFile = { file ->
    def word = new ActiveXObject("Word.Application")
    word.Visible = false

    def module = file.getParentFile().name
    println "Module: " + module

    def doc = word.Documents.Add()
    def template = doc.ListTemplates().Add()
    def level1 = template.ListLevels(1)
    level1.NumberFormat = "%1"
    level1.NumberStyle = wdListNumberStyleArabic
    level1.StartAt = 1
    doc.Styles(wdStyleHeading3).LinkToListTemplate(template)
    try {
	def model = new XmlParser().parse(file)
	//println model.title.text()
	def entities = model.entity
	println "Number of Entity: " + entities.size()
	entities.each { entity ->
	def e = new Entity()
	def entityName = entity["@entity-name"]
	def entityTitle = entity["@title"]
	e.name = entityName
	e.title = entityTitle
	println "Entity: " + entityName + " (" + entityTitle + ")"

	def fields = entity.field
	def pkeys = entity.'prim-key'
	def pks = getPKs(pkeys)
	def relations = entity.relation
	def fks = getFKs(relations)

	fields.each { field ->
	    def attr = new Attribute()
	    attr.name = field["@name"]
	    attr.domain = field["@type"]
	    attr.isPK = isPK(field["@name"], pks)
	    attr.isFK = isFK(field["@name"], fks)
	    e.attrs << attr
	}
	printEntity doc, e
	}

	// Save Document
	doc.SaveAs(System.properties['user.home'] + File.separator + "ofbiz-entitymodel-" + module + ".doc")
    } 
    finally {
	//word.Visible = true
	// Exit
	word.Quit(wdDoNotSaveChanges)
    }
}

def printer = { queue, exec ->

    try {
	File file = queue.take()
	if (file == POISON) {
	    println "Get POISON"
	    exec.shutdown()
	}
	else {
	    println "Print: " + file
	    printFile(file)
	}
	    
    }
    catch (InterruptedException e) {
        Thread.currentThread().interrup() // fail
    }

} 


def startPrinting = { roots ->
    BlockingQueue queue = new LinkedBlockingQueue(10)
    FileFilter filter = { return true } as FileFilter
    static Executor exec = Executors.newFixedThreadPool(N_THREADS)

    exec.execute({fileCrawler(queue, filter, roots)} as Runnable)

    (1..N_MODULES).each {
	exec.execute({printer(queue, exec)} as Runnable)
    }
}

def conf = new Properties()
conf.load(getClass().getResourceAsStream("/conf.properties"))

// Starting Print to Word Document
def roots = []
conf['entitymodel.dir'].tokenize(',').each { path ->
    roots << new File(path)
}

startPrinting roots

Leave a Reply





◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。