org.cristalise.dsl.module.ModuleDelegate.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cristalise-dsl Show documentation
Show all versions of cristalise-dsl Show documentation
CRISTAL-iSE Domain Specific Language module for bootstrapping and funtional testing
The newest version!
/**
* This file is part of the CRISTAL-iSE kernel.
* Copyright (c) 2001-2015 The CRISTAL Consortium. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* http://www.fsf.org/licensing/licenses/lgpl.html
*/
package org.cristalise.dsl.module
import static org.cristalise.dsl.SystemProperties.*
import static org.cristalise.dsl.lifecycle.definition.CompActDefBuilder.generateWorkflowSVG
import static org.cristalise.kernel.process.resource.BuiltInResources.PROPERTY_DESC_RESOURCE
import org.codehaus.groovy.control.CompilerConfiguration
import org.cristalise.dsl.entity.AgentBuilder
import org.cristalise.dsl.entity.AgentDelegate
import org.cristalise.dsl.entity.DomainContextBuilder
import org.cristalise.dsl.entity.DomainContextDelegate
import org.cristalise.dsl.entity.ItemBuilder
import org.cristalise.dsl.entity.ItemDelegate
import org.cristalise.dsl.entity.RoleBuilder
import org.cristalise.dsl.entity.RoleDelegate
import org.cristalise.dsl.lifecycle.definition.CompActDefBuilder
import org.cristalise.dsl.lifecycle.definition.CompActDefDelegate
import org.cristalise.dsl.lifecycle.definition.ElemActDefBuilder
import org.cristalise.dsl.lifecycle.definition.ElemActDefDelegate
import org.cristalise.dsl.lifecycle.stateMachine.StateMachineBuilder
import org.cristalise.dsl.lifecycle.stateMachine.StateMachineDelegate
import org.cristalise.dsl.persistency.outcome.SchemaBuilder
import org.cristalise.dsl.persistency.outcome.SchemaDelegate
import org.cristalise.dsl.property.PropertyDescriptionBuilder
import org.cristalise.dsl.property.PropertyDescriptionDelegate
import org.cristalise.dsl.querying.QueryBuilder
import org.cristalise.dsl.querying.QueryDelegate
import org.cristalise.dsl.scripting.ScriptBuilder
import org.cristalise.dsl.scripting.ScriptDelegate
import org.cristalise.kernel.common.InvalidDataException
import org.cristalise.kernel.entity.DomainContext
import org.cristalise.kernel.entity.imports.ImportAgent
import org.cristalise.kernel.entity.imports.ImportItem
import org.cristalise.kernel.entity.imports.ImportRole
import org.cristalise.kernel.graph.layout.DefaultGraphLayoutGenerator
import org.cristalise.kernel.lifecycle.ActivityDef
import org.cristalise.kernel.lifecycle.CompositeActivityDef
import org.cristalise.kernel.lifecycle.instance.stateMachine.StateMachine
import org.cristalise.kernel.persistency.outcome.Schema
import org.cristalise.kernel.process.Gateway
import org.cristalise.kernel.process.module.Module
import org.cristalise.kernel.process.module.ModuleActivity
import org.cristalise.kernel.process.module.ModuleAgent
import org.cristalise.kernel.process.module.ModuleConfig
import org.cristalise.kernel.process.module.ModuleDescRef
import org.cristalise.kernel.process.module.ModuleDomainContext
import org.cristalise.kernel.process.module.ModuleImport
import org.cristalise.kernel.process.module.ModuleInfo
import org.cristalise.kernel.process.module.ModuleItem
import org.cristalise.kernel.process.module.ModulePropertyDescription
import org.cristalise.kernel.process.module.ModuleQuery
import org.cristalise.kernel.process.module.ModuleRole
import org.cristalise.kernel.process.module.ModuleSchema
import org.cristalise.kernel.process.module.ModuleScript
import org.cristalise.kernel.process.module.ModuleStateMachine
import org.cristalise.kernel.process.module.ModuleWorkflow
import org.cristalise.kernel.process.resource.BuiltInResources
import org.cristalise.kernel.property.PropertyDescriptionList
import org.cristalise.kernel.querying.Query
import org.cristalise.kernel.scripting.Script
import org.cristalise.kernel.test.utils.KernelXMLUtility
import org.cristalise.kernel.utils.FileStringUtility
import org.cristalise.kernel.utils.LocalObjectLoader
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import groovy.xml.XmlUtil
/**
*
*/
@CompileStatic @Slf4j
class ModuleDelegate implements BindingConvention {
private final boolean generateResourceXml = DSL_Module_generateResourceXml.getBoolean()
private final boolean generateModuleXml = DSL_Module_generateModuleXml.getBoolean()
private final boolean strictUpdate = DSL_Module_strictUpdate.getBoolean()
private final boolean generateAllResourceItems = DSL_Module_generateAllResourceItems.getBoolean()
private Boolean updateChangedItems = null
String uploadAgentName = null
String uploadAgentPwd = null
Module module = null
Module newModule = null
Binding bindings
String resourceRoot = './src/main/resources'
String moduleDir = './src/main/module/'
private File resourceBootDir = null
private File moduleXMLFile = null
private IncludeHandler includeHandler = null
public ModuleDelegate(Map args) {
assert args.ns && args.name && args.version != null
log.info('ModuleDelegate() - args:{}', args)
inititalise(args)
addToBingings(bindings, 'moduleNs', newModule.ns as String)
addToBingings(bindings, 'moduleVersion', newModule.info.version as String)
if (moduleXMLFile.exists()) {
module = (Module) Gateway.getMarshaller().unmarshall(moduleXMLFile.text)
assert module.ns == newModule.ns
assert module.name == newModule.name
}
createModuleResourceDirectoryStructure()
boolean enableIncludeHandler = false;
if (args.containsKey('enableIncludeHandler')) {
enableIncludeHandler = args.enableIncludeHandler as boolean
}
if (enableIncludeHandler) {
includeHandler = new IncludeHandler()
includeHandler.captureModuleFileChanges(moduleDir)
generateModuleXml = false
}
}
private void createModuleResourceDirectoryStructure() {
new FileTreeBuilder(new File(resourceRoot)).dir('boot') {
for (def res : BuiltInResources.values()) {
dir(res.getTypeCode())
}
}
}
private void inititalise(Map args) {
newModule = new Module()
newModule.info = new ModuleInfo()
newModule.ns = args.ns
newModule.name = args.name
newModule.info.version = args.version
if (args.updateChangedItems != null) updateChangedItems = args.updateChangedItems as Boolean
if (args.bindings) bindings = (Binding) args.bindings
else bindings = new Binding()
if (args.resourceRoot) resourceRoot = args.resourceRoot
if (args.moduleDir) moduleDir = args.moduleDir
resourceBootDir = new File("$resourceRoot/boot")
String moduleXmlDir = args.moduleXmlDir ?: resourceRoot
moduleXMLFile = new File("$moduleXmlDir/module.xml")
if (args.userName) uploadAgentName = args.userName
if (args.userPassword) uploadAgentPwd = args.userPassword
}
public ModuleDelegate(String ns, String n, int v, Binding b = null) {
this('ns': ns, 'name': n, 'version': v, 'bindings': b)
}
private void handleInclude(String scriptFile) {
log.info('include() - scriptFile:{}', scriptFile)
CompilerConfiguration cc = new CompilerConfiguration()
cc.setScriptBaseClass(DelegatingScript.class.getName())
GroovyShell shell = new GroovyShell(this.class.classLoader, bindings, cc)
DelegatingScript script = (DelegatingScript) shell.parse(new File(scriptFile))
script.setDelegate(this)
script.run()
}
public void mandatoryInclude(String scriptFile) {
handleInclude scriptFile
}
public void include(String scriptFile) {
if (!includeHandler || includeHandler.shallInclude(scriptFile)) {
handleInclude scriptFile
}
else {
log.info('include() - SKIPPING unchanged scriptFile:{}', scriptFile)
}
}
public Schema Schema(String name, Integer version) {
log.info('Schema() - name:{} version:{}', name, version)
def schema = LocalObjectLoader.getSchema(name, version)
addSchema(schema)
return schema
}
public Schema Schema(String name, Integer version, @DelegatesTo(SchemaDelegate) Closure cl) {
log.info('Schema() - name:{} version:{}', name, version)
def sb = SchemaBuilder.build(newModule.ns, name, version, cl)
if (generateResourceXml) sb.schema.export(null, resourceBootDir, true)
sb.expressionScipts.each { script ->
if (generateResourceXml) script.export(null, resourceBootDir, true)
addScript(script)
}
addSchema(sb.schema)
return sb.schema
}
public Schema Schema(String name, Integer version, File file) {
log.info('Schema() - name:{} version:{}', name, version)
def sb = SchemaBuilder.build(newModule.ns, name, version, file)
if (generateResourceXml) sb.schema.export(null, resourceBootDir, true)
addSchema(sb.schema)
sb.expressionScipts.each { script ->
if (generateResourceXml) script.export(null, resourceBootDir, true)
addScript(script)
}
return sb.schema
}
public Query Query(String name, Integer version) {
log.info('Query() - name:{} version:{}', name, version)
def query = LocalObjectLoader.getQuery(name, version)
addQuery(query)
return query
}
public Query Query(String name, Integer version, @DelegatesTo(QueryDelegate) Closure cl) {
log.info('Query() - name:{} version:{}', name, version)
def query = QueryBuilder.build(newModule.ns, name, version, cl)
if (generateResourceXml) query.export(null, resourceBootDir, true)
addQuery(query)
return query
}
public Script Script(String name, Integer version) {
log.info('Script() - name:{} version:{}', name, version)
def script = LocalObjectLoader.getScript(name, version)
addScript(script)
return script
}
public Script Script(String name, Integer version, @DelegatesTo(ScriptDelegate) Closure cl) {
log.info('Script() - name:{} version:{}', name, version)
def sb = ScriptBuilder.build(newModule.ns, name, version, cl)
if (generateResourceXml) sb.script.export(null, resourceBootDir, true)
addScript(sb.script)
return sb.script
}
public StateMachine StateMachine(String name, Integer version) {
log.info('StateMachine() - name:{} version:{}', name, version)
def sm = LocalObjectLoader.getStateMachine(name, version)
addStateMachine(sm)
return sm
}
public StateMachine StateMachine(String name, Integer version, @DelegatesTo(StateMachineDelegate) Closure cl) {
log.info('StateMachine() - name:{} version:{}', name, version)
def sm = StateMachineBuilder.build(newModule.ns, name, version, cl).sm
if (generateResourceXml) sm.export(null, resourceBootDir, true)
addStateMachine(sm)
return sm
}
public ActivityDef Activity(String name, Integer version) {
log.info('Activity() - name:{} version:{}', name, version)
def eaDef = LocalObjectLoader.getActDef(name, version)
addActivityDef(eaDef)
return eaDef
}
public ActivityDef Activity(String name, Integer version, @DelegatesTo(ElemActDefDelegate) Closure cl) {
log.info('Activity() - name:{} version:{}', name, version)
def eaDef = ElemActDefBuilder.build(name, version, cl)
if (generateResourceXml) eaDef.export(null, resourceBootDir, true)
addActivityDef(eaDef)
return eaDef
}
public DomainContext DomainContext(String path, Integer version) {
log.info('DomainContext() - path:{} version:{}', path, version)
DomainContext context
if (path.startsWith('/')) context = new DomainContext(path, newModule.ns, version)
else context = LocalObjectLoader.getDomainContext(path, version)
if (generateResourceXml) context.export(null, resourceBootDir, true)
addDomainContext(context)
return context
}
public List Contexts(@DelegatesTo(DomainContextDelegate) Closure cl) {
log.info('Contexts()')
def domainContexts = DomainContextBuilder.build(newModule.ns, cl)
domainContexts.each { context ->
if (generateResourceXml) context.export(null, resourceBootDir, true)
addDomainContext(context)
}
return domainContexts
}
/**
*
* @param name
* @param version
* @return
*/
public CompositeActivityDef Workflow(String name, Integer version) {
log.info('Workflow() - name:{} version:{}', name, version)
def caDef = LocalObjectLoader.getCompActDef(name, version)
addCompositeActivityDef(caDef)
return caDef
}
/**
*
* @param name
* @param version
* @param cl
* @return
*/
public CompositeActivityDef Workflow(String name, Integer version, @DelegatesTo(CompActDefDelegate) Closure cl) {
return Workflow(name: name, version: version, generate: false, cl)
}
/**
*
* @param args
* @param cl
* @return
*/
public CompositeActivityDef Workflow(Map args, @DelegatesTo(CompActDefDelegate) Closure cl) {
log.info('Workflow() - name:{} version:{}', args.name, args.version)
def caDef = CompActDefBuilder.build(args, cl)
if (args?.generate) {
if (generateResourceXml) {
DefaultGraphLayoutGenerator.layoutGraph(caDef.childrenGraphModel)
//do not rebuild during export, because LocalObjectLoader will not find new actDefs declared in DSL
caDef.export(null, resourceBootDir, true, false)
if (log.isDebugEnabled()) generateWorkflowSVG('target', caDef)
}
assert caDef.verify(), args
}
else {
// since the workflow was not generated the XML file must exist
File caDir = new File(resourceBootDir, 'CA')
assert caDir.exists(), "Directory '$caDir' must exists"
String caFileName = ""+args.name + (args.version == null ? "" : "_" + args.version) + ".xml"
File caXmlFile = new File(caDir, caFileName)
assert caXmlFile.exists(), "File '$caXmlFile' must exists"
}
addCompositeActivityDef(caDef)
return caDef
}
/**
* Generates xml files for the define property description values.
* @param cl
*/
public void PropertyDescriptionList(@DelegatesTo(PropertyDescriptionDelegate) Closure cl) {
def propDescList = PropertyDescriptionBuilder.build(cl)
def type = propDescList.list.find { it.isClassIdentifier && it.name == 'Type' }
FileStringUtility.string2File(
new File(new File(resourceBootDir.path+"/"+PROPERTY_DESC_RESOURCE.typeCode), "${type.defaultValue}.xml"),
XmlUtil.serialize(Gateway.getMarshaller().marshall(propDescList))
)
}
/**
*
* @param name
* @param version
* @param cl
* @return
*/
public PropertyDescriptionList PropertyDescriptionList(String name, Integer version, @DelegatesTo(PropertyDescriptionDelegate) Closure cl) {
log.info('PropertyDescriptionList() - name:{} version:{}', name, version)
def propDescList = PropertyDescriptionBuilder.build(newModule.ns, name, version, cl)
if (generateResourceXml) propDescList.export(null, resourceBootDir, true)
addPropertyDescriptionList(propDescList)
return propDescList
}
/**
* Collects agent and add to module.xml, or update the definition it is already existing.
* @param name
* @param password
* @param cl
*/
public ImportAgent Agent(Map args, @DelegatesTo(AgentDelegate) Closure cl) {
log.info('Agent() - name:{} version:{}', args.name, args.version)
args.ns = newModule.ns
def agent = AgentBuilder.build(args, cl)
agent.roles.each { it.jobList = null }
if (generateAllResourceItems) {
if (generateResourceXml) agent.export(null, resourceBootDir, true)
addImportAgent(agent)
}
else {
//Original functionality: XML of ImportAgent is added to the module.xml
updateImports(agent)
}
return agent
}
/**
* Collects items define in the groovy scripts and add to module.xml
* or update the definition it is already existing.
* @param args
* @param cl
*/
public ImportItem Item(Map args, @DelegatesTo(ItemDelegate) Closure cl) {
log.info('Item() - name:{} version:{}', args.name, args.version)
args.ns = newModule.ns
def item = ItemBuilder.build(args, cl)
item.properties.removeAll { it.value == args.name }
if (generateAllResourceItems) {
if (generateResourceXml) item.export(null, resourceBootDir, true)
addImportItem(item)
}
else {
//Original functionality: XML of ImportItem is added to the module.xml
updateImports(item)
}
return item
}
/**
* Collects define roles and add/update on module.xml.
* @param cl
*/
public List Roles(@DelegatesTo(RoleDelegate) Closure cl) {
log.info('Roles()')
def importRoles = RoleBuilder.build(newModule.ns, cl)
importRoles.each { role ->
if (generateAllResourceItems) {
if (generateResourceXml) role.export(null, resourceBootDir, true)
addImportRole(role)
}
else {
//Original functionality: XML of ImportRole is added to the module.xml
updateImports(role)
}
}
return importRoles
}
/**
* Collects define config and add/update on module.xml.
* @param attr
*/
public void Config(Map attr) {
def config = new ModuleConfig((String) attr.name, (String) attr.value, (String) attr.target ? (String) attr.target : null)
newModule.config.add(config)
}
/**
* Collects define info and add/update on module.xml.
* @param attr
*/
public void Info(Map attr, Closure cl) {
assert attr
if (!newModule.info) newModule.info = new ModuleInfo()
if (attr.description) newModule.info.desc = (String) attr.description
if (attr.version) newModule.info.version = (String) attr.version
if (attr.kernel) newModule.info.kernelVersion = (String) attr.kernel
if (cl) {
def dependencies = cl()
if (dependencies) newModule.info.dependency.addAll(dependencies)
}
}
/**
* Sets the module's resourceUrl value.
* @param url
* @return
*/
public Url(String url){
assert url
newModule.resURL = url
}
private void generateModuleXML() {
log.info('generateModuleXML()')
def oldModuleXML = XmlUtil.serialize(Gateway.getMarshaller().marshall(module))
def newModuleXML = XmlUtil.serialize(Gateway.getMarshaller().marshall(newModule))
KernelXMLUtility.compareXML(oldModuleXML, newModuleXML)
FileStringUtility.string2File(moduleXMLFile, newModuleXML)
}
private void updateChangedItems() {
log.info('updateChangedItems()')
def agent = Gateway.getSecurityManager().authenticate(uploadAgentName, uploadAgentPwd, null)
def uploader = new ResourceUpdateHandler(agent, newModule.ns, "${resourceRoot}/boot", includeHandler?.changedScriptFiles)
uploader.updateChanges()
}
public void processClosure(Closure cl) {
assert cl
assert newModule.name
cl.delegate = this
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
if (generateModuleXml) generateModuleXML()
if (updateChangedItems) {
updateChangedItems()
}
else if (includeHandler && includeHandler.changedScriptFiles) {
String msg = "Check if Script XML files were updated. Consider enabling ResourceUpdate feature - files:${includeHandler.changedScriptFiles}"
throw new InvalidDataException(msg)
}
}
/**
* Validate if the StateMachine is existing or not. If not it will be added to the module's resources.
*
* @param sm
*/
private void addStateMachine(StateMachine sm) {
addToBingings(bindings, sm)
ModuleStateMachine moduleSm = new ModuleStateMachine()
moduleSm.setVersion(sm.version)
moduleSm.setName(sm.name)
moduleSm.setNamespace(sm.namespace)
updateImports(moduleSm)
}
/**
* Validate if the Query is existing or not. If not it will be added to the module's resources.
*
* @param obj
*/
private void addQuery(Query query) {
addToBingings(bindings, query)
ModuleQuery moduleQuery = new ModuleQuery()
moduleQuery.setVersion(query.version)
moduleQuery.setName(query.name)
moduleQuery.setNamespace(query.namespace)
updateImports(moduleQuery)
}
/**
* Validate if the Schema is existing or not. If not it will be added to the module's resources.
*
* @param obj
*/
private void addSchema(Schema schema) {
addToBingings(bindings, schema)
ModuleSchema moduleSchema = new ModuleSchema()
moduleSchema.setVersion(schema.version)
moduleSchema.setName(schema.name)
moduleSchema.setNamespace(schema.namespace)
updateImports(moduleSchema)
}
/**
* Validate if the Script is existing or not. If not it will be added to the module's resources.
*
* @param obj
*/
private void addScript(Script script) {
addToBingings(bindings, script)
ModuleScript moduleScript = new ModuleScript()
moduleScript.setVersion(script.version)
moduleScript.setName(script.name)
moduleScript.setNamespace(script.namespace)
updateImports(moduleScript)
}
private void addDomainContext(DomainContext context) {
addToBingings(bindings, context)
def moduleContext = new ModuleDomainContext()
moduleContext.setNamespace(context.namespace)
moduleContext.setName(context.name)
moduleContext.setVersion(context.version)
updateImports(moduleContext)
}
/**
* Validate if the activity is existing and has been updated. If not existing it will be added, if updated it will update the details.
*
* @param obj
*/
private void addActivityDef(ActivityDef actDef) {
addToBingings(bindings, actDef)
ModuleActivity moduleAct = new ModuleActivity()
moduleAct.setVersion(actDef.version)
moduleAct.setName(actDef.name)
if (actDef.script) moduleAct.setScript(new ModuleDescRef(actDef.script.name, null, actDef.script.version))
if (actDef.schema) moduleAct.setSchema(new ModuleDescRef(actDef.schema.name, null, actDef.schema.version))
if (actDef.query) moduleAct.setQuery( new ModuleDescRef(actDef.query.name, null, actDef.query.version))
//Do not add 'Default' StateMachine
if (actDef.stateMachine && actDef.stateMachine.name != StateMachine.getDefaultStateMachine('Elementary')) {
moduleAct.setStateMachine( new ModuleDescRef(actDef.stateMachine.name, null, actDef.stateMachine.version))
}
updateImports(moduleAct)
}
/**
*
* @param caDef
*/
private void addCompositeActivityDef(CompositeActivityDef caDef) {
addToBingings(bindings, caDef)
ModuleWorkflow moduleWf = new ModuleWorkflow()
moduleWf.setVersion(caDef.version)
moduleWf.setName(caDef.name)
if (caDef.refChildActDef) {
caDef.refChildActDef.each {
ActivityDef act = ActivityDef.cast(it)
moduleWf.activities.add(new ModuleDescRef(act.name, null/*act.itemID*/, act.version))
}
}
//Do not add 'CompositeActivity' StateMachine
if (caDef.stateMachine && caDef.stateMachine.name != StateMachine.getDefaultStateMachine('Composite')) {
moduleWf.setStateMachine( new ModuleDescRef(caDef.stateMachine.name, null, caDef.stateMachine.version))
}
updateImports(moduleWf)
}
private void addPropertyDescriptionList(PropertyDescriptionList pdl) {
addToBingings(bindings, pdl)
def modulePropDesc = new ModulePropertyDescription()
modulePropDesc.setVersion(pdl.version)
modulePropDesc.setName(pdl.name)
modulePropDesc.setNamespace(pdl.namespace)
updateImports(modulePropDesc)
}
private void addImportAgent(ImportAgent agent) {
addToBingings(bindings, agent)
def moduleAgent = new ModuleAgent()
moduleAgent.setName(agent.name)
moduleAgent.setVersion(agent.version)
moduleAgent.setNamespace(agent.namespace)
updateImports(moduleAgent)
}
private void addImportItem(ImportItem item) {
addToBingings(bindings, item)
def moduleItem = new ModuleItem()
moduleItem.setName(item.name)
moduleItem.setVersion(item.version)
moduleItem.setNamespace(item.namespace)
updateImports(moduleItem)
}
private void addImportRole(ImportRole role) {
addToBingings(bindings, role)
def moduleRole = new ModuleRole()
moduleRole.setName(role.name)
moduleRole.setVersion(role.version)
moduleRole.setNamespace(role.namespace)
updateImports(moduleRole)
}
private void updateImports(ModuleImport mImport) {
int index = newModule.imports.list.findIndexOf {
ModuleImport mi -> (mi.name == mImport.name) && (mi.getClass() == mImport.getClass())
}
if (index > -1 && generateModuleXml) {
def msg = "Cannot update existing import:$mImport.name, class:${mImport.getClass().getSimpleName()}"
if (strictUpdate) throw new InvalidDataException(msg)
else log.warn(msg)
}
if (index > -1) newModule.imports.list.set(index, mImport)
else newModule.imports.list.add(mImport)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy