2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.sal.java.api.generator
10 import com.google.common.collect.ImmutableList
11 import com.google.common.collect.Lists
12 import com.google.common.collect.Range
13 import com.google.common.io.BaseEncoding
14 import java.beans.ConstructorProperties
15 import java.math.BigDecimal
16 import java.math.BigInteger
17 import java.util.ArrayList
18 import java.util.Arrays
19 import java.util.Collections
21 import java.util.regex.Pattern
22 import org.opendaylight.yangtools.binding.generator.util.TypeConstants
23 import org.opendaylight.yangtools.sal.binding.model.api.Constant
24 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
25 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
26 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
27 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
28 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
29 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
30 import com.google.common.base.Preconditions
33 * Template for generating JAVA class.
35 class ClassTemplate extends BaseTemplate {
37 protected val List<GeneratedProperty> properties
38 protected val List<GeneratedProperty> finalProperties
39 protected val List<GeneratedProperty> parentProperties
40 protected val Iterable<GeneratedProperty> allProperties;
41 protected val Restrictions restrictions
44 * List of enumeration which are generated as JAVA enum type.
46 protected val List<Enumeration> enums
49 * List of constant instances which are generated as JAVA public static final attributes.
51 protected val List<Constant> consts
54 * List of generated types which are enclosed inside <code>genType</code>
56 protected val List<GeneratedType> enclosedGeneratedTypes;
58 protected val GeneratedTransferObject genTO;
61 * Creates instance of this class with concrete <code>genType</code>.
63 * @param genType generated transfer object which will be transformed to JAVA class source code
65 new(GeneratedTransferObject genType) {
68 this.properties = genType.properties
69 this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)
70 this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)
71 this.restrictions = genType.restrictions
73 var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();
74 sorted.addAll(properties);
75 sorted.addAll(parentProperties);
76 Collections.sort(sorted, [p1, p2|
77 p1.name.compareTo(p2.name)
80 this.allProperties = sorted
81 this.enums = genType.enumerations
82 this.consts = genType.constantDefinitions
83 this.enclosedGeneratedTypes = genType.enclosedTypes
87 * Generates JAVA class source code (class body only).
89 * @return string with JAVA class body source code
91 def CharSequence generateAsInnerClass() {
92 return generateBody(true)
95 override protected body() {
100 * Template method which generates class body.
102 * @param isInnerClass boolean value which specify if generated class is|isn't inner
103 * @return string with class source code in JAVA format
105 def protected generateBody(boolean isInnerClass) '''
106 «wrapToDocumentation(formatDataForJavaDoc(type))»
107 «generateClassDeclaration(isInnerClass)» {
109 «innerClassesDeclarations»
111 «constantsDeclarations»
114 «IF restrictions != null && (!restrictions.rangeConstraints.nullOrEmpty ||
115 !restrictions.lengthConstraints.nullOrEmpty)»
116 «generateConstraints»
123 «FOR field : properties SEPARATOR "\n"»
130 «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
131 «generateGetValueForBitsTypeDef»
138 «generateToString(genTO.toStringIdentifiers)»
140 «generateLengthMethod("length", "_length")»
142 «generateRangeMethod("range", "_range")»
149 * Template method which generates the method <code>getValue()</code> for typedef,
150 * which base type is BitsDefinition.
152 * @return string with the <code>getValue()</code> method definition in JAVA format
154 def protected generateGetValueForBitsTypeDef() '''
156 public boolean[] getValue() {
157 return new boolean[]{
158 «FOR property: genTO.properties SEPARATOR ','»
165 def private generateLengthMethod(String methodName, String varName) '''
166 «IF restrictions != null && !(restrictions.lengthConstraints.empty)»
167 «val numberClass = restrictions.lengthConstraints.iterator.next.min.class»
169 * @deprecated This method is slated for removal in a future release. See BUG-1485 for details.
172 public static «List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> «methodName»() {
178 def private generateRangeMethod(String methodName, String varName) '''
179 «IF restrictions != null && !(restrictions.rangeConstraints.empty)»
180 «val returnType = allProperties.iterator.next.returnType»
182 * @deprecated This method is slated for removal in a future release. See BUG-1485 for details.
185 public static «List.importedName»<«Range.importedName»<«returnType.importedNumber»>> «methodName»() {
192 * Template method which generates inner classes inside this interface.
194 * @return string with the source code for inner classes in JAVA format
196 def protected innerClassesDeclarations() '''
197 «IF !enclosedGeneratedTypes.empty»
198 «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
199 «IF (innerClass instanceof GeneratedTransferObject)»
200 «val classTemplate = new ClassTemplate(innerClass)»
201 «classTemplate.generateAsInnerClass»
208 def protected constructors() '''
210 «genUnionConstructor»
212 «allValuesConstructor»
214 «IF !allProperties.empty»
217 «IF properties.empty && !parentProperties.empty »
222 def private generateConstraints() '''
224 «IF !restrictions.rangeConstraints.nullOrEmpty»
225 «generateRangeConstraints»
227 «IF !restrictions.lengthConstraints.nullOrEmpty»
228 «generateLengthConstraints»
233 private def generateRangeConstraints() '''
234 «IF !allProperties.nullOrEmpty»
235 «val returnType = allProperties.iterator.next.returnType»
236 «IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)»
237 «rangeBody(restrictions, BigDecimal, genTO.importedName, "_range")»
239 «rangeBody(restrictions, BigInteger, genTO.importedName, "_range")»
244 private def rangeBody(Restrictions restrictions, Class<? extends Number> numberClass, String className, String varName) '''
245 «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder();
246 «FOR r : restrictions.rangeConstraints»
247 builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»));
249 «varName» = builder.build();
252 private def lengthBody(Restrictions restrictions, Class<? extends Number> numberClass, String className, String varName) '''
253 «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder();
254 «FOR r : restrictions.lengthConstraints»
255 builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»));
257 «varName» = builder.build();
260 private def generateLengthConstraints() '''
261 «IF restrictions != null && !(restrictions.lengthConstraints.empty)»
262 «val numberClass = restrictions.lengthConstraints.iterator.next.min.class»
263 «IF numberClass.equals(typeof(BigDecimal))»
264 «lengthBody(restrictions, numberClass, genTO.importedName, "_length")»
266 «lengthBody(restrictions, typeof(BigInteger), genTO.importedName, "_length")»
271 def protected allValuesConstructor() '''
272 «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
273 @«ConstructorProperties.importedName»("value")
275 public «type.name»(«allProperties.asArgumentsDeclaration») {
276 «IF false == parentProperties.empty»
277 super(«parentProperties.asArguments»);
279 «FOR p : allProperties»
280 «generateRestrictions(type, p.fieldName.toString, p.returnType)»
284 * If we have patterns, we need to apply them to the value field. This is a sad
285 * consequence of how this code is structured.
287 IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
289 «Preconditions.importedName».checkNotNull(_value, "Supplied value may not be null");
292 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME && c.value instanceof List<?>»
293 for (Pattern p : patterns) {
294 «Preconditions.importedName».checkArgument(p.matcher(_value).matches(), "Supplied value \"%s\" does not match any of the permitted patterns %s", _value, «TypeConstants.PATTERN_CONSTANT_NAME»);
302 «IF p.returnType.importedName.contains("[]")»
303 this.«p.fieldName» = «p.fieldName» == null ? null : «p.fieldName».clone();
305 this.«p.fieldName» = «p.fieldName»;
312 def protected genUnionConstructor() '''
313 «FOR p : allProperties»
314 «val List<GeneratedProperty> other = new ArrayList(properties)»
316 «genConstructor(p, other)»
322 def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''
323 public «type.name»(«property.returnType.importedName + " " + property.name») {
324 «IF false == parentProperties.empty»
325 super(«parentProperties.asArguments»);
328 «generateRestrictions(type, property.fieldName.toString, property.returnType)»
330 this.«property.fieldName» = «property.name»;
332 this.«p.fieldName» = null;
337 def protected copyConstructor() '''
339 * Creates a copy from Source Object.
341 * @param source Source object
343 public «type.name»(«type.name» source) {
344 «IF false == parentProperties.empty»
348 this.«p.fieldName» = source.«p.fieldName»;
353 def protected parentConstructor() '''
355 * Creates a new instance from «genTO.superType.importedName»
357 * @param source Source object
359 public «type.name»(«genTO.superType.importedName» source) {
364 def protected defaultInstance() '''
365 «IF genTO.typedef && !allProperties.empty && !genTO.unionType»
366 «val prop = allProperties.get(0)»
367 «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))»
368 public static «genTO.name» getDefaultInstance(String defaultValue) {
369 «IF "byte[]".equals(prop.returnType.name)»
370 «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64();
371 return new «genTO.name»(baseEncoding.decode(defaultValue));
372 «ELSEIF "java.lang.String".equals(prop.returnType.fullyQualifiedName)»
373 return new «genTO.name»(defaultValue);
374 «ELSEIF allProperties.size > 1»
376 «ELSEIF "java.lang.Boolean".equals(prop.returnType.fullyQualifiedName)»
377 return new «genTO.name»(Boolean.valueOf(defaultValue));
378 «ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)»
379 return new «genTO.name»(Byte.valueOf(defaultValue));
380 «ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)»
381 return new «genTO.name»(Short.valueOf(defaultValue));
382 «ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)»
383 return new «genTO.name»(Integer.valueOf(defaultValue));
384 «ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)»
385 return new «genTO.name»(Long.valueOf(defaultValue));
387 return new «genTO.name»(new «prop.returnType.importedName»(defaultValue));
394 def protected bitsArgs() '''
395 «List.importedName»<«String.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»);
396 if (!properties.contains(defaultValue)) {
397 throw new «IllegalArgumentException.importedName»("invalid default parameter");
400 return new «genTO.name»(
401 «FOR prop : allProperties SEPARATOR ","»
402 properties.get(i++).equals(defaultValue) ? «Boolean.importedName».TRUE : null
407 def protected propsAsArgs(Iterable<GeneratedProperty> properties) '''
408 «FOR prop : properties SEPARATOR ","»
414 * Template method which generates JAVA class declaration.
416 * @param isInnerClass boolean value which specify if generated class is|isn't inner
417 * @return string with class declaration in JAVA format
419 def protected generateClassDeclaration(boolean isInnerClass) '''
423 ELSEIF (type.abstract)»«
427 ENDIF»class «type.name»«
428 IF (genTO.superType != null)»«
429 " extends "»«genTO.superType.importedName»«
431 «IF (!type.implements.empty)»«
433 FOR type : type.implements SEPARATOR ", "»«
440 * Template method which generates JAVA enum type.
442 * @return string with inner enum source code in JAVA format
444 def protected enumDeclarations() '''
446 «FOR e : enums SEPARATOR "\n"»
447 «val enumTemplate = new EnumTemplate(e)»
448 «enumTemplate.generateAsInnerClass»
453 def protected suidDeclaration() '''
454 «IF genTO.SUID != null»
455 private static final long serialVersionUID = «genTO.SUID.value»L;
460 * Template method which generates JAVA constants.
462 * @return string with constants in JAVA format
464 def protected constantsDeclarations() '''
467 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
468 «val cValue = c.value»
469 «IF cValue instanceof List<?>»
470 private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST»;
471 public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
472 FOR v : cValue SEPARATOR ", "»«
473 IF v instanceof String»"«
478 «generateStaticInicializationBlock»
481 public static final «c.type.importedName» «c.name» = «c.value»;
488 * Template method which generates JAVA static initialization block.
490 * @return string with static initialization block in JAVA format
492 def protected generateStaticInicializationBlock() '''
494 final «List.importedName»<«Pattern.importedName»> l = new «ArrayList.importedName»<«Pattern.importedName»>();
495 for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {
496 l.add(Pattern.compile(regEx));
499 «Constants.MEMBER_PATTERN_LIST» = «ImmutableList.importedName».copyOf(l);
504 * Template method which generates JAVA class attributes.
506 * @return string with the class attributes in JAVA format
508 def protected generateFields() '''
509 «IF restrictions != null»
510 «val prop = getPropByName("value")»
512 «IF !(restrictions.lengthConstraints.empty)»
513 private static final «List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _length;
515 «IF !(restrictions.rangeConstraints.empty)»
516 private static final «List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _range;
520 «IF !properties.empty»
522 private«IF f.readOnly» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
528 * Template method which generates the method <code>hashCode()</code>.
530 * @return string with the <code>hashCode()</code> method definition in JAVA format
532 def protected generateHashCode() '''
533 «IF !genTO.hashCodeIdentifiers.empty»
535 public int hashCode() {
536 final int prime = 31;
538 «FOR property : genTO.hashCodeIdentifiers»
539 «IF property.returnType.name.contains("[")»
540 result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));
542 result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());
551 * Template method which generates the method <code>equals()</code>.
553 * @return string with the <code>equals()</code> method definition in JAVA format
555 def protected generateEquals() '''
556 «IF !genTO.equalsIdentifiers.empty»
558 public boolean equals(java.lang.Object obj) {
565 if (getClass() != obj.getClass()) {
568 «type.name» other = («type.name») obj;
569 «FOR property : genTO.equalsIdentifiers»
570 «val fieldName = property.fieldName»
571 if («fieldName» == null) {
572 if (other.«fieldName» != null) {
575 «IF property.returnType.name.contains("[")»
576 } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {
578 } else if(!«fieldName».equals(other.«fieldName»)) {
588 def GeneratedProperty getPropByName(String name) {
589 for (GeneratedProperty prop : allProperties) {
590 if (prop.name.equals(name)) {