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=ef40bb1c0cccbce81c056c431f753da903a33812;hb=c78147a97c8a158ddd06897c26042f17ce6dfe53;hp=152d60e6de6b5f933addf4714e41f4da702dbae7;hpb=343b90cbc5eb6a9d202bb4a322067b5c52bf6f65;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 152d60e6de..ef40bb1c0c 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,8 +7,8 @@ */ package org.opendaylight.yangtools.sal.java.api.generator -import com.google.common.collect.ImmutableList -import com.google.common.collect.Range +import com.google.common.base.CharMatcher +import com.google.common.base.Splitter import java.math.BigDecimal import java.math.BigInteger import java.util.Arrays @@ -17,6 +17,7 @@ import java.util.HashMap import java.util.List import java.util.Map import java.util.StringTokenizer +import java.util.regex.Pattern 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.GeneratedProperty @@ -25,13 +26,16 @@ 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; - private static final String NEW_LINE = '\n' + private static final char NEW_LINE = '\n' + private static final CharMatcher NL_MATCHER = CharMatcher.is(NEW_LINE) + private static final CharMatcher TAB_MATCHER = CharMatcher.is('\t') + private static final Pattern SPACES_PATTERN = Pattern.compile(" +") + private static final Splitter NL_SPLITTER = Splitter.on(NL_MATCHER) new(GeneratedType _type) { if (_type == null) { @@ -57,10 +61,10 @@ abstract class BaseTemplate { '''.toString } - protected def imports() ''' + protected def imports() ''' «IF !importMap.empty» «FOR entry : importMap.entrySet» - «IF entry.value != fullyQualifiedName» + «IF !hasSamePackage(entry.value)» import «entry.value».«entry.key»; «ENDIF» «ENDFOR» @@ -68,6 +72,17 @@ abstract class BaseTemplate { ''' + /** + * Checks if packages of generated type and imported type is the same + * + * @param importedTypePackageNam + * the package name of imported type + * @return true if the packages are the same false otherwise + */ + final private def boolean hasSamePackage(String importedTypePackageName) { + return type.packageName.equals(importedTypePackageName); + } + protected abstract def CharSequence body(); // Helper patterns @@ -87,15 +102,19 @@ abstract class BaseTemplate { /** * Template method which generates the getter method for field - * - * @param field + * + * @param field * generated property with data about field which is generated as the getter method - * @return string with the getter method source code in JAVA format + * @return string with the getter method source code in JAVA format */ final protected def getterMethod(GeneratedProperty field) { ''' public «field.returnType.importedName» «field.getterMethodName»() { + «IF field.returnType.importedName.contains("[]")» + return «field.fieldName» == null ? null : «field.fieldName».clone(); + «ELSE» return «field.fieldName»; + «ENDIF» } ''' } @@ -107,10 +126,10 @@ abstract class BaseTemplate { /** * Template method which generates the setter method for field - * - * @param field + * + * @param field * generated property with data about field which is generated as the setter method - * @return string with the setter method source code in JAVA format + * @return string with the setter method source code in JAVA format */ final protected def setterMethod(GeneratedProperty field) ''' «val returnType = field.returnType.importedName» @@ -131,7 +150,7 @@ abstract class BaseTemplate { /** * Template method which generates method parameters with their types from parameters. - * + * * @param parameters * group of generated property instances which are transformed to the method parameters * @return string with the list of the method parameters with their types in JAVA format @@ -141,26 +160,24 @@ abstract class BaseTemplate { /** * Template method which generates sequence of the names of the class attributes from parameters. - * - * @param parameters + * + * @param parameters * group of generated property instances which are transformed to the sequence of parameter names - * @return string with the list of the parameter names of the parameters + * @return string with the list of the parameter names of the parameters */ def final protected asArguments(Iterable parameters) '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter. fieldName»«ENDFOR»«ENDIF»''' /** * Template method which generates JAVA comments. - * + * * @param comment string with the comment for whole JAVA class * @return string with comment in JAVA format */ def protected CharSequence asJavadoc(String comment) { if(comment == null) return '' var txt = comment - if (txt.contains("*/")) { - txt = txt.replace("*/", "*/") - } + txt = comment.trim txt = formatToParagraph(txt) @@ -170,18 +187,18 @@ abstract class BaseTemplate { } def String wrapToDocumentation(String text) { - val StringTokenizer tokenizer = new StringTokenizer(text, "\n", false) - val StringBuilder sb = new StringBuilder() - - if(text.empty) + if (text.empty) return "" - sb.append("/**") + val StringBuilder sb = new StringBuilder("/**") sb.append(NEW_LINE) - while(tokenizer.hasMoreTokens) { - sb.append(" * ") - sb.append(tokenizer.nextToken) + for (String t : NL_SPLITTER.split(text)) { + sb.append(" *") + if (!t.isEmpty()) { + sb.append(' '); + sb.append(t) + } sb.append(NEW_LINE) } sb.append(" */") @@ -190,7 +207,7 @@ abstract class BaseTemplate { } def protected String formatDataForJavaDoc(GeneratedType type) { - val typeDescription = type.getDescription(); + val typeDescription = type.getDescription().encodeJavadocSymbols; return ''' «IF !typeDescription.nullOrEmpty» @@ -199,13 +216,48 @@ abstract class BaseTemplate { '''.toString } + private static final CharMatcher AMP_MATCHER = CharMatcher.is('&'); + private static final CharMatcher GT_MATCHER = CharMatcher.is('>'); + private static final CharMatcher LT_MATCHER = CharMatcher.is('<'); + + def encodeJavadocSymbols(String description) { + if (description.nullOrEmpty) { + return description; + } + + var ret = description.replace("*/", "*/") + + // FIXME: Use Guava's HtmlEscapers once we have it available + ret = AMP_MATCHER.replaceFrom(ret, "&"); + ret = GT_MATCHER.replaceFrom(ret, ">"); + ret = LT_MATCHER.replaceFrom(ret, "<"); + return ret; + } + + def protected String formatDataForJavaDoc(GeneratedType type, String additionalComment) { + val StringBuilder typeDescription = new StringBuilder(); + if (!type.description.nullOrEmpty) { + typeDescription.append(type.description) + typeDescription.append(NEW_LINE) + typeDescription.append(NEW_LINE) + typeDescription.append(NEW_LINE) + typeDescription.append(additionalComment) + } else { + typeDescription.append(additionalComment) + } + + return ''' + «typeDescription.toString» + '''.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(",")) { + if (text.endsWith('.') || text.endsWith(':') || text.endsWith(',')) { tempText = text.substring(0, text.length - 1) lastChar = text.charAt(text.length - 1) badEnding = true @@ -231,10 +283,10 @@ abstract class BaseTemplate { var StringBuilder lineBuilder = new StringBuilder(); var boolean isFirstElementOnNewLineEmptyChar = false; - formattedText = formattedText.replace("*/", "*/") - formattedText = formattedText.replace(NEW_LINE, "") - formattedText = formattedText.replace("\t", "") - formattedText = formattedText.replaceAll(" +", " "); + formattedText = formattedText.encodeJavadocSymbols + formattedText = NL_MATCHER.removeFrom(formattedText) + formattedText = TAB_MATCHER.removeFrom(formattedText) + formattedText = SPACES_PATTERN.matcher(formattedText).replaceAll(" ") val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true); @@ -255,8 +307,9 @@ abstract class BaseTemplate { lineBuilder.setLength(0) sb.append(NEW_LINE) - if(nextElement.toString == ' ') + if(nextElement.toString == ' ') { isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar; + } } if(isFirstElementOnNewLineEmptyChar) { @@ -273,63 +326,6 @@ abstract class BaseTemplate { 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(returnType, restrictions, paramName, isNestedType)» - «ENDIF» - «IF !restrictions.rangeConstraints.empty» - «generateRangeRestriction(returnType, paramName, isNestedType)» - «ENDIF» - «ENDIF» - ''' - - 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; - 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: %s, expected: %s.", «paramName», «IF isNestedType»«returnType.importedName».«ENDIF»length())); - } - } - ''' - - def private generateRangeRestriction(Type returnType, String paramName, boolean isNestedType) ''' - if («paramName» != null) { - «printRangeConstraint(returnType, paramName, isNestedType)» - boolean isValidRange = false; - 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», «IF isNestedType»«returnType.importedName».«ENDIF»range())); - } - } - ''' - /** * Print length constraint. * This should always be a BigInteger (only string and binary can have length restriction) @@ -338,32 +334,11 @@ abstract class BaseTemplate { «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.importedName» toString() { - «StringBuilder.importedName» builder = new «StringBuilder.importedName»("«type.name» ["); + «StringBuilder.importedName» builder = new «StringBuilder.importedName»(«type.importedName».class.getSimpleName()).append(" ["); boolean first = true; «FOR property : properties» @@ -389,9 +364,9 @@ abstract class BaseTemplate { def getRestrictions(Type type) { var Restrictions restrictions = null if (type instanceof ConcreteType) { - restrictions = (type as ConcreteType).restrictions + restrictions = type.restrictions } else if (type instanceof GeneratedTransferObject) { - restrictions = (type as GeneratedTransferObject).restrictions + restrictions = type.restrictions } return restrictions } @@ -411,7 +386,7 @@ abstract class BaseTemplate { /** * Template method which generates method parameters with their types from parameters. - * + * * @param parameters * list of parameter instances which are transformed to the method parameters * @return string with the list of the method parameters with their types in JAVA format @@ -424,76 +399,6 @@ abstract class BaseTemplate { ENDIF »''' - def protected generateLengthMethod(String methodName, Type type, String className, String varName) ''' - «val Restrictions restrictions = type.restrictions» - «IF restrictions != null && !(restrictions.lengthConstraints.empty)» - «val numberClass = restrictions.lengthConstraints.iterator.next.min.class» - public static «List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> «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 @@ -536,7 +441,7 @@ abstract class BaseTemplate { return "new " + number + "(\"" + value + "\")" } - def private GeneratedProperty findProperty(GeneratedTransferObject gto, String name) { + def protected GeneratedProperty findProperty(GeneratedTransferObject gto, String name) { val props = gto.properties for (prop : props) { if (prop.name.equals(name)) {