Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract binding closures #19

Merged
merged 8 commits into from
Aug 20, 2018
16 changes: 16 additions & 0 deletions src/main/groovy/de/lisaplus/atlas/builder/JsonSchemaBuilder.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,22 @@ class JsonSchemaBuilder implements IModelBuilder {
propertyParent.properties.each { propObj ->
propList.add(creeateSimpleProperty(model, parentName,currentSchemaPath,propObj))
}
// Dirty hack for enabling the usage of mongoDB Index2d:
// For performing filtering on geo coordinates in Documents of the mongoDB (e.g. operation geoWithin), the Json
// document containing the coordinates must have the longitude/X coordinate as first property and the latitude/Y
// coordinate as second property (property names are irrelevant!).
// But as JsonSlurper reorders the properties in alphabetic sequence, we can not force the necessary
// longitude / latitude sequence by defining it in the model json.
// Therefore this code tests for the existence of the properties lon and lat. If both are present,
// then the properties are reordered so that lon and lat come first!
Property lonProp = propList.find {prop -> prop.name == 'lon'}
Property latProp = propList.find {prop -> prop.name == 'lat'}
if (lonProp && latProp) {
propList.remove(lonProp)
propList.remove(latProp)
propList.add(0, latProp)
propList.add(0, lonProp)
}
return propList
}

Expand Down
310 changes: 21 additions & 289 deletions src/main/groovy/de/lisaplus/atlas/codegen/GeneratorBase.groovy
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
package de.lisaplus.atlas.codegen

import de.lisaplus.atlas.DoCodeGen
import de.lisaplus.atlas.codegen.helper.java.JavaTypeConvert
import de.lisaplus.atlas.codegen.helper.java.JsonTypeConvert
import de.lisaplus.atlas.codegen.helper.java.SwaggerTypeConvert
import de.lisaplus.atlas.model.ComplexType
import de.lisaplus.atlas.model.InnerType
import de.lisaplus.atlas.model.Model
import de.lisaplus.atlas.model.Property
import de.lisaplus.atlas.model.RefType
import de.lisaplus.atlas.model.Type
import groovy.text.GStringTemplateEngine
import groovy.text.Template
import groovy.text.TemplateEngine
import groovy.text.XmlTemplateEngine
import groovy.text.markup.MarkupTemplateEngine
import org.codehaus.groovy.runtime.StringBufferWriter
import org.slf4j.Logger


/**
* Created by eiko on 05.06.17.
*/
abstract class GeneratorBase {
abstract class GeneratorBase extends TypeStringManipulation {
Template template

static void createDir(String dirName) {
Expand Down Expand Up @@ -137,297 +128,38 @@ abstract class GeneratorBase {
}

/**
* methon create a map object and initialize it with some basic stuff
* @param model
* method create a map object and initialize it with some basic string manipulation stuff
* needed for working with the types and their properties in the templates.
* @return
*/
Map createTemplateDataMap(Model model) {
return [
model:model,
DOLLAR:'$',
toLowerCase: toLowerCase,
toUpperCase: toUpperCase,
firstLowerCase: firstLowerCase,
firstUpperCase: firstUpperCase,
lowerCamelCase: firstLowerCamelCase,
upperCamelCase: firstUpperCamelCase,
isInnerType: isInnerType,
isPropComplexType: isPropComplexType,
typeToJava: JavaTypeConvert.convert,
typeToSwagger: SwaggerTypeConvert.convert,
typeToJson: JsonTypeConvert.convert,
typeToMeta: JsonTypeConvert.meta,
typeFormatToSwagger: SwaggerTypeConvert.format,
typeFormatToJson: JsonTypeConvert.format,
renderInnerTemplate: renderInnerTemplate,
breakTxt: breakTxt,
containsTag: containsTag,
missingTag: missingTag,
containsPropName: containsPropName,
missingPropName: missingPropName,
propsContainsTag: propsContainsTag,
filterProps: filterProps,
filterPropsPerform: filterPropsPerform,
printLines: printLines
]
}

Closure<List<Property>> filterProps = { Type type, Map params ->
// def filterProps = { type, params ->
List props = type.properties
if (params.filterCls!= null) props = props.findAll { params.get('filterCls') }
if (params.name != null) props = props.findAll { prop -> prop.name == params.name }
if (params.namePattern != null) props = props.findAll { prop -> prop.name =~ params.namePattern }
if (params.complex != null) props = props.findAll { prop -> prop.isComplexType() == params.complex }
if (params.refComplex != null) props = props.findAll { prop ->
// println "refComplex: param=${params.refComplex} propName=${prop.name} propValue=${prop.isRefTypeOrComplexType()}"
prop.isRefTypeOrComplexType() == params.refComplex }
if (params.array != null) props = props.findAll { prop -> prop.type.isArray == params.array }
if (params.join != null) props = props.findAll { prop ->
// def evaled = prop.hasTag('join') == params.join
// println "join: param=${params.join} propName=${prop.name} propValue=${prop.hasTag('join')} evaled=${evaled}"
prop.hasTag('join') == params.join }
if (params.aggregation != null) props = props.findAll { prop -> prop.isAggregation() == params.aggregation }
if (params.implRefIsRef != null) props = props.findAll { prop -> prop.implicitRefIsRefType() == params.implRefIsRef }
if (params.implRefIsComp != null) props = props.findAll { prop -> prop.implicitRefIsComplexType() == params.implRefIsComp }
if (params.typeName!= null) props = props.findAll { prop -> prop.type.NAME == params.typeName }
if (params.typeNameNot!= null) props = props.findAll { prop -> prop.type.NAME != params.typeNameNot }
// Alternative: use pattern, e.g. typeNamePattern:'^(?!DATE$)' to get all types with names other than 'DATE'
if (params.typeNamePattern!= null) props = props.findAll { prop -> prop.type.NAME =~ params.typeNamePattern }
if (params.hasTag != null) props = props.findAll { prop -> prop.hasTag(params.hasTag) }
if (params.withoutTag != null) props = props.findAll { prop -> !prop.hasTag(params.withoutTag) }
return props
}

// Closure<List<String>> filterPropsPerform = {Type type, Map params, Closure<Property> toLines ->
def filterPropsPerform = { type, params, toLines ->
def props = filterProps.call(type, params)
def lines = []
if (props.size() > 0 && params.comment != null) {
lines += params.comment
}
// props.each { prop -> lines = lines + toLines.call(prop) }
props.each { prop -> lines += toLines.call(prop) }
if (props.size() > 0 && true == params.newLine) {
lines += ''
}
return lines
}


// Closure<Void> printLines3 = { Writer out, Map params, List... lists ->
// Vararg definition is mandatory, call example: printLines3.call( [level:2, by: '.-'], new StringWriter(), list, list2 )
def printLines = { out, params,List... lists ->
def level = params.level?:0
def by = params.by?:' '
def prefix = ''
level.times { prefix += by}
lists.flatten().each { out << "$prefix$it\n" }
}

def isInnerType = { type ->
return type && (type instanceof InnerType )
}

def isPropComplexType = { prop ->
return prop && prop.type && (prop.type instanceof ComplexType || prop.type instanceof RefType)
}

def containsTag = { obj, tag ->
if (! tag ) return false
if (! ((obj instanceof Type) || (obj instanceof Property))) {
return false
}
if (!obj.tags) {
return false
}
return obj.tags.contains(tag)
}

def containsPropName = { type, propName ->
if (! type ) return false
if (! propName ) return false
if (! (type instanceof Type)) return false
return type.properties.findIndexOf{
it.name==propName
} != -1
}

def missingPropName = { type, propName ->
if (! type ) return false
if (! propName ) return false
if (! (type instanceof Type)) return false
return type.properties.findIndexOf{
it.name==propName
} == -1
}

def missingTag = { obj, tag ->
if (! tag ) return false
if (! ((obj instanceof Type) || (obj instanceof Property))) {
return false
}
if (!obj.tags) {
return false
}
return ! obj.tags.contains(tag)
}

def propsContainsTag = { type, name ->
if (! type ) return false
if (! name ) return false
if (! (type instanceof Type)) {
return false
}
def result = type.properties.find { it.tags.contains(name) }
if (result) {
return true
}
else {
return false
}
}

def breakTxt = { String txtToBreak,int charPerLine,String breakText='\n' ->
if (!txtToBreak) return EMPTY
StringBuilder sb = new StringBuilder()
int txtLen = txtToBreak.length()
int aktPos = 0
while (aktPos < txtLen) {
if ((aktPos + charPerLine) >= txtLen) {
// The rest of the word is smaller than the desired char count per line
sb.append(txtToBreak.substring(aktPos))
break;
} else {
sb.append(txtToBreak.substring(aktPos, aktPos + charPerLine))
aktPos += charPerLine
if (txtToBreak.substring(aktPos, aktPos + 1) == ' ') {
sb.append(breakText)
aktPos++
} else {
for (aktPos; aktPos < txtLen; aktPos++) {
String subStr = txtToBreak.substring(aktPos, aktPos + 1)
if (subStr == ' ') {
sb.append(breakText)
aktPos++
break
} else {
sb.append(subStr)
}
}
}
}
}
return sb.toString()
}

def toLowerCase = { str ->
return str==null ? EMPTY : str.toLowerCase()
/*
Map getClosures() {
return new TypeStringManipulation().getClosures()
}
*/

def toUpperCase = { str ->
return str==null ? EMPTY : str.toUpperCase()
/**
* method create a map object and initialize it with some basic stuff
* @param model
* @return
*/
Map createTemplateDataMap(Model model) {
Map map = getClosures()
map.model = model
map.renderInnerTemplate = renderInnerTemplate
return map
}

def renderInnerTemplate = { templateResource,actObj,indent ->
def test = actObj.toString()
def innerTemplate = createTemplateFromResource(templateResource,TemplateType.GString)
def data = [
actObj: actObj,
indent: indent,
printIndent: printIndent,
DOLLAR:'$',
toLowerCase: toLowerCase,
toUpperCase: toUpperCase,
firstLowerCase: firstLowerCase,
firstUpperCase: firstUpperCase,
lowerCamelCase: firstLowerCamelCase,
upperCamelCase: firstUpperCamelCase,
isInnerType: isInnerType,
typeToJava: JavaTypeConvert.convert,
typeToSwagger: SwaggerTypeConvert.convert,
typeToJson: JsonTypeConvert.convert,
typeToMeta: JsonTypeConvert.meta,
typeFormatToSwagger: SwaggerTypeConvert.format,
typeFormatToJson: JsonTypeConvert.format,
renderInnerTemplate: renderInnerTemplate,
breakTxt: breakTxt,
filterProps: filterProps,
filterPropsPerform: filterPropsPerform,
printLines: printLines
]

def data = getClosures()
data.actObj = actObj
data.indent = indent
data.renderInnerTemplate = renderInnerTemplate
return innerTemplate.make(data)
}

def printIndent = { indent ->
def ret = ''
for (def i=0;i<indent;i++) ret+=' '
return ret
}

def firstLowerCase = { str ->
if (!str) return EMPTY
def first = str.substring(0,1)
first = first.toLowerCase()
if (str.length()>1) {
def rest = str.substring(1)
return first + rest
}
else {
return first
}
}

def firstUpperCase = { str ->
if (!str) return EMPTY
def first = str.substring(0,1)
first = first.toUpperCase()
if (str.length()>1) {
def rest = str.substring(1)
return first + rest
}
else {
return first
}
}

def firstUpperCamelCase = { str ->
if (!str) return EMPTY
def firstUpper = firstUpperCase(str)
return convertAllUnderLinesToCamelCase(firstUpper)
}

def firstLowerCamelCase = { str ->
if (!str) return EMPTY
def firstLower = firstLowerCase(str)
return convertAllUnderLinesToCamelCase(firstLower)
}

def convertAllUnderLinesToCamelCase = { String str ->
if (!str) return EMPTY
def i_ = str.indexOf('_')
while (i_!=-1) {
def stopLen = str.length()-1
if (i_<stopLen) {
def nextChar = new String(str.charAt(i_+1))
if (nextChar=='_') {
str = str.replace('__','_')
}
else {
def nextCharUpper = nextChar.toUpperCase()
str = str.replace('_'+nextChar,new String(nextCharUpper))
}
}
else
break
i_ = str.indexOf('_',i_)
}
return str
}

private final static String EMPTY=''

abstract String getDestFileName(Model dataModel, Map<String,String> extraParameters,Type currentType=null)
abstract String getDestDir(Model dataModel, String outputBasePath, Map<String,String> extraParameters,Type currentType=null)

Expand Down
Loading