X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=code-generator%2Fbinding-java-api-generator%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fsal%2Fjava%2Fapi%2Fgenerator%2FBaseTemplate.xtend;h=152d60e6de6b5f933addf4714e41f4da702dbae7;hb=refs%2Fchanges%2F44%2F9144%2F15;hp=625b3424abdc80cdcb1f7c343226a427a0c30aff;hpb=40541e307e2dcb438a9fd5aea2b624407cd8caf9;p=yangtools.git diff --git a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BaseTemplate.xtend b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BaseTemplate.xtend index 625b3424ab..152d60e6de 100644 --- a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BaseTemplate.xtend +++ b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BaseTemplate.xtend @@ -7,34 +7,38 @@ */ package org.opendaylight.yangtools.sal.java.api.generator -import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty -import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType -import java.util.Map -import org.opendaylight.yangtools.sal.binding.model.api.Type -import org.opendaylight.yangtools.binding.generator.util.Types -import com.google.common.base.Splitter -import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature +import com.google.common.collect.ImmutableList import com.google.common.collect.Range -import java.util.ArrayList +import java.math.BigDecimal +import java.math.BigInteger +import java.util.Arrays +import java.util.Collection +import java.util.HashMap import java.util.List +import java.util.Map +import java.util.StringTokenizer +import org.opendaylight.yangtools.binding.generator.util.Types import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType -import org.opendaylight.yangtools.sal.binding.model.api.Restrictions +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject -import java.util.Collection -import java.util.Arrays +import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType +import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature +import org.opendaylight.yangtools.sal.binding.model.api.Restrictions +import org.opendaylight.yangtools.sal.binding.model.api.Type +import org.opendaylight.yangtools.yang.common.QName abstract class BaseTemplate { - protected val GeneratedType type; protected val Map importMap; - static val paragraphSplitter = Splitter.on("\n\n").omitEmptyStrings(); + + private static final String NEW_LINE = '\n' new(GeneratedType _type) { if (_type == null) { throw new IllegalArgumentException("Generated type reference cannot be NULL!") } this.type = _type; - this.importMap = GeneratorUtil.createImports(type) + this.importMap = new HashMap() } def packageDefinition() '''package «type.packageName»;''' @@ -48,7 +52,7 @@ abstract class BaseTemplate { ''' «packageDefinition» «imports» - + «_body» '''.toString } @@ -61,7 +65,7 @@ abstract class BaseTemplate { «ENDIF» «ENDFOR» «ENDIF» - + ''' protected abstract def CharSequence body(); @@ -152,128 +156,228 @@ abstract class BaseTemplate { * @return string with comment in JAVA format */ def protected CharSequence asJavadoc(String comment) { - if(comment == null) return ''; + if(comment == null) return '' var txt = comment if (txt.contains("*/")) { txt = txt.replace("*/", "*/") } - val paragraphs = paragraphSplitter.split(txt) + txt = comment.trim + txt = formatToParagraph(txt) return ''' - /** - «FOR p : paragraphs SEPARATOR "

"» - «p» - «ENDFOR» - **/ + «wrapToDocumentation(txt)» ''' } - def generateRestrictions(Type type, String paramName, Type returnType) ''' - «val boolean isArray = returnType.name.contains("[")» - «processRestrictions(type, paramName, returnType, isArray)» - ''' + def String wrapToDocumentation(String text) { + val StringTokenizer tokenizer = new StringTokenizer(text, "\n", false) + val StringBuilder sb = new StringBuilder() - def generateRestrictions(GeneratedProperty field, String paramName) ''' - «val Type type = field.returnType» - «IF type instanceof ConcreteType» - «processRestrictions(type, paramName, field.returnType, type.name.contains("["))» - «ELSEIF type instanceof GeneratedTransferObject» - «processRestrictions(type, paramName, field.returnType, isArrayType(type as GeneratedTransferObject))» - «ENDIF» - ''' + if(text.empty) + return "" + + sb.append("/**") + sb.append(NEW_LINE) + + while(tokenizer.hasMoreTokens) { + sb.append(" * ") + sb.append(tokenizer.nextToken) + sb.append(NEW_LINE) + } + sb.append(" */") + + return sb.toString + } + + def protected String formatDataForJavaDoc(GeneratedType type) { + val typeDescription = type.getDescription(); + + return ''' + «IF !typeDescription.nullOrEmpty» + «typeDescription» + «ENDIF» + '''.toString + } + + def asLink(String text) { + val StringBuilder sb = new StringBuilder() + var tempText = text + var char lastChar = ' ' + var boolean badEnding = false + + if(text.endsWith(".") || text.endsWith(":") || text.endsWith(",")) { + tempText = text.substring(0, text.length - 1) + lastChar = text.charAt(text.length - 1) + badEnding = true + } + sb.append("") + sb.append(tempText) + sb.append("") + + if(badEnding) + sb.append(lastChar) + + return sb.toString + } + + protected def formatToParagraph(String text) { + if(text == null || text.isEmpty) + return text + var formattedText = text + val StringBuilder sb = new StringBuilder(); + var StringBuilder lineBuilder = new StringBuilder(); + var boolean isFirstElementOnNewLineEmptyChar = false; + + formattedText = formattedText.replace("*/", "*/") + formattedText = formattedText.replace(NEW_LINE, "") + formattedText = formattedText.replace("\t", "") + formattedText = formattedText.replaceAll(" +", " "); + + val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true); + + while(tokenizer.hasMoreElements) { + val nextElement = tokenizer.nextElement.toString + + if(lineBuilder.length + nextElement.length > 80) { + if (lineBuilder.charAt(lineBuilder.length - 1) == ' ') { + lineBuilder.setLength(0) + lineBuilder.append(lineBuilder.substring(0, lineBuilder.length - 1)) + } + if (lineBuilder.charAt(0) == ' ') { + lineBuilder.setLength(0) + lineBuilder.append(lineBuilder.substring(1)) + } + + sb.append(lineBuilder); + lineBuilder.setLength(0) + sb.append(NEW_LINE) + + if(nextElement.toString == ' ') + isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar; + } - private def processRestrictions(Type type, String paramName, Type returnType, boolean isArray) ''' + if(isFirstElementOnNewLineEmptyChar) { + isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar + } + + else { + lineBuilder.append(nextElement) + } + } + sb.append(lineBuilder) + sb.append(NEW_LINE) + + return sb.toString + } + + def isDocumentationParametersNullOrEmtpy(GeneratedType type) { + val boolean isTypeDescriptionNullOrEmpty = type.description.nullOrEmpty + val boolean isTypeReferenceNullOrEmpty = type.reference.nullOrEmpty + val boolean isTypeModuleNameNullOrEmpty = type.moduleName.nullOrEmpty + val boolean isTypeSchemaPathNullOrEmpty = type.schemaPath.nullOrEmpty + + if (isTypeDescriptionNullOrEmpty && isTypeReferenceNullOrEmpty && isTypeModuleNameNullOrEmpty + && isTypeSchemaPathNullOrEmpty) { + return true + } + return false + } + + def generateRestrictions(Type type, String paramName, Type returnType) ''' «val restrictions = type.getRestrictions» «IF restrictions !== null» + «val boolean isNestedType = !(returnType instanceof ConcreteType)» «IF !restrictions.lengthConstraints.empty» - «generateLengthRestriction(type, restrictions, paramName, isArray, - !(returnType instanceof ConcreteType))» + «generateLengthRestriction(returnType, restrictions, paramName, isNestedType)» «ENDIF» - «IF !restrictions.rangeConstraints.empty && - ("java.lang".equals(returnType.packageName) || "java.math".equals(returnType.packageName))» - «generateRangeRestriction(type, returnType, restrictions, paramName, - !(returnType instanceof ConcreteType))» + «IF !restrictions.rangeConstraints.empty» + «generateRangeRestriction(returnType, paramName, isNestedType)» «ENDIF» «ENDIF» ''' - def generateLengthRestriction(Type type, Restrictions restrictions, String paramName, boolean isArray, - boolean isNestedType) ''' + def private generateLengthRestriction(Type returnType, Restrictions restrictions, String paramName, boolean isNestedType) ''' + «val clazz = restrictions.lengthConstraints.iterator.next.min.class» if («paramName» != null) { + «printLengthConstraint(returnType, clazz, paramName, isNestedType, returnType.name.contains("["))» boolean isValidLength = false; - «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList. - importedName»<>(); - «FOR r : restrictions.lengthConstraints» - lengthConstraints.add(«Range.importedName».closed(«r.min», «r.max»)); - «ENDFOR» - for («Range.importedName»<«Integer.importedName»> r : lengthConstraints) { - «IF isArray» - «IF isNestedType» - if (r.contains(«paramName».getValue().length)) { - «ELSE» - if (r.contains(«paramName».length)) { - «ENDIF» - «ELSE» - «IF isNestedType» - if (r.contains(«paramName».getValue().length())) { - «ELSE» - if (r.contains(«paramName».length())) { - «ENDIF» - «ENDIF» - isValidLength = true; + for («Range.importedName»<«clazz.importedNumber»> r : «IF isNestedType»«returnType.importedName».«ENDIF»length()) { + if (r.contains(_constraint)) { + isValidLength = true; } } if (!isValidLength) { - throw new IllegalArgumentException(String.format("Invalid length: {}, expected: {}.", «paramName», lengthConstraints)); + throw new IllegalArgumentException(String.format("Invalid length: %s, expected: %s.", «paramName», «IF isNestedType»«returnType.importedName».«ENDIF»length())); } } ''' - def generateRangeRestriction(Type type, Type returnType, Restrictions restrictions, String paramName, - boolean isNestedType) ''' - «val javaType = Class.forName(returnType.fullyQualifiedName)» + def private generateRangeRestriction(Type returnType, String paramName, boolean isNestedType) ''' if («paramName» != null) { + «printRangeConstraint(returnType, paramName, isNestedType)» boolean isValidRange = false; - «List.importedName»<«Range.importedName»<«javaType.importedName»>> rangeConstraints = new «ArrayList. - importedName»<>(); - «FOR r : restrictions.rangeConstraints» - rangeConstraints.add(«Range.importedName».closed(new «javaType.importedName»(«r.min.toQuote»), new «javaType. - importedName»(«r.max.toQuote»))); - «ENDFOR» - for («Range.importedName»<«javaType.importedName»> r : rangeConstraints) { - «IF isNestedType» - if (r.contains(«paramName».getValue())) { - «ELSE» - if (r.contains(«paramName»)) { - «ENDIF» - isValidRange = true; + for («Range.importedName»<«returnType.importedNumber»> r : «IF isNestedType»«returnType.importedName».«ENDIF»range()) { + if (r.contains(_constraint)) { + isValidRange = true; } } if (!isValidRange) { - throw new IllegalArgumentException(String.format("Invalid range: %s, expected: %s.", «paramName», rangeConstraints)); + throw new IllegalArgumentException(String.format("Invalid range: %s, expected: %s.", «paramName», «IF isNestedType»«returnType.importedName».«ENDIF»range())); } } ''' + /** + * Print length constraint. + * This should always be a BigInteger (only string and binary can have length restriction) + */ + def printLengthConstraint(Type returnType, Class clazz, String paramName, boolean isNestedType, boolean isArray) ''' + «clazz.importedNumber» _constraint = «clazz.importedNumber».valueOf(«paramName»«IF isNestedType».getValue()«ENDIF».length«IF !isArray»()«ENDIF»); + ''' + + def printRangeConstraint(Type returnType, String paramName, boolean isNestedType) ''' + «IF BigDecimal.canonicalName.equals(returnType.fullyQualifiedName)» + «BigDecimal.importedName» _constraint = new «BigDecimal.importedName»(«paramName»«IF isNestedType».getValue()«ENDIF».toString()); + «ELSE» + «IF isNestedType» + «val propReturnType = findProperty(returnType as GeneratedTransferObject, "value").returnType» + «IF propReturnType.fullyQualifiedName.equals(BigInteger.canonicalName)» + «BigInteger.importedName» _constraint = «paramName».getValue(); + «ELSE» + «BigInteger.importedName» _constraint = «BigInteger.importedName».valueOf(«paramName».getValue()); + «ENDIF» + «ELSE» + «IF returnType.fullyQualifiedName.equals(BigInteger.canonicalName)» + «BigInteger.importedName» _constraint = «paramName»; + «ELSE» + «BigInteger.importedName» _constraint = «BigInteger.importedName».valueOf(«paramName»); + «ENDIF» + «ENDIF» + «ENDIF» + ''' + def protected generateToString(Collection properties) ''' «IF !properties.empty» @Override - public String toString() { - StringBuilder builder = new StringBuilder("«type.name» ["); + public «String.importedName» toString() { + «StringBuilder.importedName» builder = new «StringBuilder.importedName»("«type.name» ["); boolean first = true; - «FOR i : 0..> «methodName»() { + «IF numberClass.equals(typeof(BigDecimal))» + «lengthBody(restrictions, numberClass, className, varName)» + «ELSE» + «lengthBody(restrictions, typeof(BigInteger), className, varName)» + «ENDIF» + } + «ENDIF» + ''' + + def private lengthBody(Restrictions restrictions, Class numberClass, String className, String varName) ''' + if («varName» == null) { + synchronized («className».class) { + if («varName» == null) { + «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder(); + «FOR r : restrictions.lengthConstraints» + builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»)); + «ENDFOR» + «varName» = builder.build(); + } + } + } + return «varName»; + ''' + + def protected generateRangeMethod(String methodName, Restrictions restrictions, Type returnType, String className, String varName) ''' + «IF restrictions != null && !(restrictions.rangeConstraints.empty)» + «val number = returnType.importedNumber» + public static «List.importedName»<«Range.importedName»<«number»>> «methodName»() { + «IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)» + «rangeBody(restrictions, BigDecimal, className, varName)» + «ELSE» + «rangeBody(restrictions, BigInteger, className, varName)» + «ENDIF» + } + «ENDIF» + ''' + + def protected generateRangeMethod(String methodName, Restrictions restrictions, String className, String varName, Iterable properties) ''' + «IF restrictions != null && !(restrictions.rangeConstraints.empty)» + «val returnType = properties.iterator.next.returnType» + public static «List.importedName»<«Range.importedName»<«returnType.importedNumber»>> «methodName»() { + «IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)» + «rangeBody(restrictions, BigDecimal, className, varName)» + «ELSE» + «rangeBody(restrictions, BigInteger, className, varName)» + «ENDIF» + } + «ENDIF» + ''' + + def private rangeBody(Restrictions restrictions, Class numberClass, String className, String varName) ''' + if («varName» == null) { + synchronized («className».class) { + if («varName» == null) { + «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder(); + «FOR r : restrictions.rangeConstraints» + builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»)); + «ENDFOR» + «varName» = builder.build(); + } + } + } + return «varName»; + ''' + + def protected String importedNumber(Class clazz) { + if (clazz.equals(typeof(BigDecimal))) { + return BigDecimal.importedName + } + return BigInteger.importedName + } + + def protected String importedNumber(Type clazz) { + if (clazz.fullyQualifiedName.equals(BigDecimal.canonicalName)) { + return BigDecimal.importedName + } + return BigInteger.importedName + } + + def protected String numericValue(Class clazz, Object numberValue) { + val number = clazz.importedName; + val value = numberValue.toString + if (clazz.equals(typeof(BigInteger)) || clazz.equals(typeof(BigDecimal))) { + if (value.equals("0")) { + return number + ".ZERO" + } else if (value.equals("1")) { + return number + ".ONE" + } else if (value.equals("10")) { + return number + ".TEN" + } else { + try { + val Long longVal = Long.valueOf(value) + return number + ".valueOf(" + longVal + "L)" + } catch (NumberFormatException e) { + if (clazz.equals(typeof(BigDecimal))) { + try { + val Double doubleVal = Double.valueOf(value); + return number + ".valueOf(" + doubleVal + ")" + } catch (NumberFormatException e2) { + } + } + } + } + } + return "new " + number + "(\"" + value + "\")" + } + + def private GeneratedProperty findProperty(GeneratedTransferObject gto, String name) { + val props = gto.properties + for (prop : props) { + if (prop.name.equals(name)) { + return prop + } + } + val GeneratedTransferObject parent = gto.superType + if (parent != null) { + return findProperty(parent, name) + } + return null + } + }