Binding generator v2 - fix IdentifiableItem and Item
[mdsal.git] / binding2 / mdsal-binding2-java-api-generator / src / main / twirl / org / opendaylight / mdsal / binding / javav2 / java / api / generator / builderTemplate.scala.txt
1 @*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  *@
8
9 @import java.util.List
10 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.fieldName
11 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.formatDataForJavaDocBuilder
12 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.getSimpleNameForBuilder
13 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.getterMethodName
14 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.getRestrictions
15 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.propertyNameFromGetter
16 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.toFirstUpper
17 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.wrapToDocumentation
18 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers.BuilderRenderer.getAllIfcs
19 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers.BuilderRenderer.hasImplementsFromUses
20 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers.BuilderRenderer.toListOfNames
21 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.AbstractRangeGenerator
22 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.LengthGenerator
23 @import org.opendaylight.mdsal.binding.javav2.model.api.ConcreteType
24 @import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType
25 @import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTypeForBuilder
26 @import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject
27 @import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty
28 @import org.opendaylight.mdsal.binding.javav2.model.api.Type
29 @import org.opendaylight.yangtools.concepts.Builder
30
31 @(genType: GeneratedType, properties: Set[GeneratedProperty], importedNames: Map[String, String],
32 ImportedNamesWithProperties: Map[GeneratedProperty, String], augmentField: GeneratedProperty, copyConstructorHelper: String,
33 getterMethods: List[String], parentTypeForBuilderName: String, childTreeNode: Boolean, childTreeNodeIdent: Boolean,
34 keyTypeName: String, instantiable: Boolean)
35 @if(genType != null) {
36 @{wrapToDocumentation(formatDataForJavaDocBuilder(importedNames.get("genType")))}
37 public class @{genType.getName}Builder implements @{getSimpleNameForBuilder} <@{importedNames.get("genType")}> {
38
39     @generateFields(false)
40
41     @generateAugmentField(false)
42
43     @generateConstructorsFromIfcs()
44
45     @generateCopyConstructor(false)
46
47     @generateMethodFieldsFrom()
48
49     @generateGetters(false)
50
51     @generateSetters()
52
53     @@Override
54     public @{genType.getName} build() {
55         return new @{genType.getName}Impl(this);
56     }
57
58     private static final class @{genType.getName}Impl implements @{genType.getName} {
59     @if(instantiable) {
60         @implementedInterfaceGetter()
61     }
62
63         @generateFields(true)
64
65         @generateAugmentField(true)
66
67         @generateCopyConstructor(true)
68
69         @generateGetters(true)
70
71         @generateHashCode()
72
73         @generateEquals()
74
75         @generateToString()
76
77         @generateImplementedMethods()
78     }
79 }
80 }
81
82 @**
83  * Template method which generates class attributes.
84  *
85  * @param isFinal value which specify whether field is|isn't final
86  * @param genType is genType
87  * @return string with class attributes and their types
88  *@
89 @generateFields(isFinal: Boolean) = {
90     @if(ImportedNamesWithProperties != null) {
91         @for((key, value) <- ImportedNamesWithProperties) {
92             private @if(isFinal) { final}
93             @{value} @{fieldName(key)};
94         }
95     }
96 }
97
98 @**
99  * Template method which generates class attributes.
100  *
101  * @param boolean value which specify whether field is|isn't final
102  * @return string with class attributes and their types
103  *@
104 @generateAugmentField(isPrivate: Boolean) = {
105     @if(augmentField != null) {
106         @if(isPrivate) {private }
107         @{importedNames.get("map")}<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>,
108         @{importedNames.get("augmentFieldReturnType")}> @{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
109     }
110 }
111
112 @implementedInterfaceGetter() = {
113     @@Override
114     public @{importedNames.get("class")}<@{importedNames.get("genType")}> implementedInterface() {
115     return @{importedNames.get("genType")}.class;
116     }
117 }
118
119 @**
120  * Generate default constructor and constructor for every implemented interface from uses statements.
121  *@
122 @generateConstructorsFromIfcs() = {
123     public @{genType.getName}Builder() {
124     }
125     @if(genType.isInstanceOf[GeneratedType] && !genType.isInstanceOf[GeneratedTransferObject]) {
126         @for(impl <- genType.asInstanceOf[GeneratedType].getImplements) {
127             @generateConstructorFromIfc(impl)
128         }
129     }
130 }
131
132 @generateMethodFieldsFrom() = {
133     @if(genType.isInstanceOf[GeneratedType] && genType.isInstanceOf[GeneratedTypeForBuilder]
134             && !genType.isInstanceOf[GeneratedTransferObject]) {
135         @if(hasImplementsFromUses(genType.asInstanceOf[GeneratedType])) {
136             /**
137              * Set fields from given grouping argument. Valid argument is instance of one of following types:
138              * <ul>
139              @for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
140              * <li>@{impl.getFullyQualifiedName}</li>
141              }
142              * </ul>
143              *
144              * @@param arg grouping object
145              * @@throws IllegalArgumentException if given argument is none of valid types
146             */
147
148             public void fieldsFrom(@{importedNames.get("treeNode")} arg) {
149                 boolean isValidArg = false;
150                 @for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
151                     @if(impl.isInstanceOf[GeneratedType] && impl.isInstanceOf[GeneratedTypeForBuilder]
152                             && !impl.asInstanceOf[GeneratedType].getMethodDefinitions.isEmpty) {
153                         if (arg instanceof @{impl.asInstanceOf[GeneratedType].getFullyQualifiedName}) {
154                             @if(impl.isInstanceOf[GeneratedType] && impl.isInstanceOf[GeneratedTypeForBuilder]
155                                     && !impl.isInstanceOf[GeneratedTransferObject]) {
156                                 @for(getter <- impl.asInstanceOf[GeneratedType].getMethodDefinitions) {
157                                     this._@{propertyNameFromGetter(getter)} = ((@{impl.asInstanceOf[GeneratedType].getFullyQualifiedName})arg).@{getter.getName}();
158                                 }
159                             }
160                             isValidArg = true;
161                         }
162                     }
163                 }
164                 if (!isValidArg) {
165                     throw new IllegalArgumentException(
166                       "expected one of: @{toListOfNames(getAllIfcs(genType.asInstanceOf[GeneratedType]))} \n" +
167                       "but was: " + arg
168                     );
169                 }
170             }
171         }
172     }
173 }
174
175 @**
176  * Generate constructor with argument of given type.
177  *@
178 @generateConstructorFromIfc(impl: Type) = {
179     @if(impl.isInstanceOf[GeneratedType] && impl.isInstanceOf[GeneratedTypeForBuilder]) {
180         @if(!impl.asInstanceOf[GeneratedType].getMethodDefinitions.isEmpty) {
181             public @{genType.getName}Builder(
182             @{impl.getFullyQualifiedName} arg) {
183             @{printConstructorPropertySetter(impl)}
184             }
185         }
186         @for(implTypeImplement <- impl.asInstanceOf[GeneratedType].getImplements) {
187             @generateConstructorFromIfc(implTypeImplement)
188         }
189     }
190 }
191
192 @printConstructorPropertySetter(implementedIfc: Type) = {
193     @if(implementedIfc.isInstanceOf[GeneratedType] && !implementedIfc.isInstanceOf[GeneratedTransferObject]) {
194         @for(getter <- implementedIfc.asInstanceOf[GeneratedType].getMethodDefinitions) {
195             this._@{propertyNameFromGetter(getter)} = arg.@{getter.getName}();
196         }
197         @for(impl <- implementedIfc.asInstanceOf[GeneratedType].getImplements) {
198             @{printConstructorPropertySetter(impl)}
199         }
200     }
201 }
202
203 @generateImplType() = {
204 @defining(genType.getName + "Impl") {typeImpl => @typeImpl}
205 }
206
207 @generateBuilderType() = {
208 @defining(genType.getName + "Builder") {typeBuilder => @typeBuilder}
209 }
210
211 @generateInnerBuilderType() = {
212 @defining("(" + genType.getName + "Builder base)") {typeInnerBuilder => @typeInnerBuilder}
213 }
214
215 @generateInnerType() = {
216 @defining("(" + genType.getName + " base)") {innerType => @innerType}
217 }
218
219 @generateCopyConstructor(impl: Boolean) = {
220     @if(impl) {private} else {public}
221     @if(impl) {@generateImplType()} else {@generateBuilderType()}
222     @if(impl) {@generateInnerBuilderType()} else {@generateInnerType()}
223     {
224     @{copyConstructorHelper}
225     @if(augmentField != null) {
226         @if(impl) {
227             switch (base.@{augmentField.getName}.size()) {
228             case 0:
229                 this.@{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
230                 break;
231             case 1:
232                 final @{importedNames.get("map")}.Entry<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e = base.@{augmentField.getName}.entrySet().iterator().next();
233                 this.@{augmentField.getName} = @{importedNames.get("collections")}.<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> singletonMap(e.getKey(), e.getValue());
234                 break;
235             default :
236                 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(base.@{augmentField.getName});
237             }
238         } else {
239             if (base instanceof @{genType.getName}Impl) {
240                 @{genType.getName}Impl impl = (@{genType.getName}Impl) base;
241                 if (!impl.@{augmentField.getName}.isEmpty()) {
242                     this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(impl.@{augmentField.getName});
243                 }
244             } @{"else"} if (base instanceof @{importedNames.get("augmentationHolder")}) {
245                 @@SuppressWarnings("unchecked")
246                 @{importedNames.get("augmentationHolder")}<@{importedNames.get("genType")}> casted =(@{importedNames.get("augmentationHolder")}<@{importedNames.get("genType")}>) base;
247                 if (!casted.augmentations().isEmpty()) {
248                     this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(casted.augmentations());
249                 }
250             }
251         }
252     }
253     }
254 }
255
256
257 @generateSetters() = {
258     @for(field <- properties) {
259         @if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
260             @if(getRestrictions(field.getReturnType).getRangeConstraint.isPresent) {
261                 @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeChecker(toFirstUpper(field.getName),
262                 getRestrictions(field.getReturnType).getRangeConstraint.get)}
263             }
264             @if(getRestrictions(field.getReturnType).getLengthConstraint.isPresent) {
265                 @{LengthGenerator.generateLengthChecker(fieldName(field), field.getReturnType,
266                 getRestrictions(field.getReturnType).getLengthConstraint.get)}
267             }
268         }
269
270         public @{genType.getName}Builder set@{toFirstUpper(field.getName)}(final @{field.getReturnType.getFullyQualifiedName} value) {
271         @if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
272             if (value != null) {
273             @if(getRestrictions(field.getReturnType).getRangeConstraint.isPresent) {
274                 @if(field.getReturnType.isInstanceOf[ConcreteType]) {
275                     @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value")}
276                 } else {
277                     @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value.getValue()")}
278                 }
279             }
280             @if(getRestrictions(field.getReturnType).getLengthConstraint.isPresent) {
281                 @if(field.getReturnType.isInstanceOf[ConcreteType]) {
282                     @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value")}
283                 } else {
284                     @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value.getValue()")}
285                 }
286             }
287             }
288         }
289             this.@{fieldName(field)} = value;
290             return this;
291         }
292     }
293     @if(augmentField != null) {
294         public @{genType.getName}Builder add@{toFirstUpper(augmentField.getName)}(@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}> augmentationType, @{importedNames.get("augmentFieldReturnType")} augmentation) {
295             if (augmentation == null) {
296                 return remove@{toFirstUpper(augmentField.getName)}(augmentationType);
297             }
298
299             if (!(this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")})) {
300                 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>();
301             }
302
303             this.@{augmentField.getName}.put(augmentationType, augmentation);
304             return this;
305         }
306
307         public @{genType.getName}Builder remove@{toFirstUpper(augmentField.getName)}
308         (@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}> augmentationType) {
309             if (this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")}) {
310                 this.@{augmentField.getName}.remove(augmentationType);
311             }
312             return this;
313         }
314     }
315 }
316
317 @generateGetters(addOverride: Boolean) = {
318     @if(!getterMethods.isEmpty) {
319         @for(property <- getterMethods) {
320             @if(addOverride) {@@Override}
321             @{property}
322         }
323     }
324     @if(augmentField != null) {
325         @@SuppressWarnings("unchecked")
326         @if(addOverride) {@@Override}
327         public <E extends @{importedNames.get("augmentation")}<? super @{genType.getName}>> E get@{toFirstUpper(augmentField.getName)}
328         (@{importedNames.get("class")}<E> augmentationType) {
329             if (augmentationType == null) {
330                 throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
331             }
332             return (E) @{augmentField.getName}.get(augmentationType);
333         }
334     }
335 }
336
337 @generateHashCode() = {
338     @if(!properties.isEmpty || augmentField != null) {
339         private int hash = 0;
340         private volatile boolean hashValid = false;
341
342         @@Override
343         public int hashCode() {
344             if (hashValid) {
345                 return hash;
346             }
347
348             final int prime = 31;
349             int result = 1;
350             @for(property <- properties) {
351                 @if(property.getReturnType.getName.contains("[")) {
352                     result = prime * result + @{importedNames.get("arrays")}.hashCode(@{fieldName(property)});
353                 } else {
354                     result = prime * result + @{importedNames.get("objects")}.hashCode(@{fieldName(property)});
355                 }
356             }
357             @if(augmentField != null) {
358                 result = prime * result + @{importedNames.get("objects")}.hashCode(@{augmentField.getName});
359             }
360
361             hash = result;
362             hashValid = true;
363             return result;
364         }
365     }
366 }
367
368 @generateToString() = {
369     @if(properties != null) {
370         @@Override
371         public @{importedNames.get("string")} toString() {
372             @{importedNames.get("string")} name = "@{genType.getName} [";
373             @{importedNames.get("stringBuilder")} builder = new @{importedNames.get("stringBuilder")}(name);
374             @for((property, index) <- properties.zipWithIndex) {
375                 if (@{fieldName(property)} != null) {
376                     builder.append("@{fieldName(property)}=");
377                     @if(property.getReturnType.getName.contains("[")) {
378                         builder.append(@{importedNames.get("arrays")}.toString(@{fieldName(property)}));
379                     } else {
380                         builder.append(@{fieldName(property)});
381                     }
382                     @if(properties.size() > 1 && index < properties.size()-1){
383                         builder.append(", ");
384                     }
385                 }
386             }
387             @if(augmentField != null) {
388                 @if(!properties.isEmpty()){
389                     final int builderLength = builder.length();
390                     final int builderAdditionalLength = builder.substring(name.length(), builderLength).length();
391                     if (builderAdditionalLength > 2 && !builder.substring(builderLength - 2, builderLength).equals(", ")) {
392                         builder.append(", ");
393                     }
394                 }
395                 builder.append("@{augmentField.getName}=");
396                 builder.append(@{augmentField.getName}.values());
397                 return builder.append(']').toString();
398             } else {
399                 @if(properties.isEmpty()){
400                     return builder.append(']').toString();
401                 } else {
402                     return builder.append(']').toString();
403                 }
404             }
405         }
406     }
407 }
408
409 @generateImplementedMethods() = {
410     @if(childTreeNodeIdent) {
411         @@Override
412         public @{importedNames.get("identifiableItem")}<@{genType.getName()}, @{keyTypeName}> treeIdentifier() {
413             return new @{importedNames.get("identifiableItem")}(@{importedNames.get("genType")}.class,_identifier);
414         }
415     } else {
416       @if(childTreeNode) {
417           @@Override
418           public @{importedNames.get("item")}<@{genType.getName()}> treeIdentifier() {
419                return new @{importedNames.get("item")}(@{importedNames.get("genType")}.class);
420           }
421       }
422     }
423
424     @if(augmentField != null) {
425         @@Override
426         public @{importedNames.get("classInstMap")}<@{importedNames.get("augmentation")}<? super @{genType.getName}>>
427         augments() {
428             //TODO implement
429             return null;
430         }
431     }
432 }
433
434 @generateEquals() = {
435     @if(!properties.isEmpty || augmentField != null) {
436         @@Override
437         public boolean equals(@{importedNames.get("object")} obj) {
438             if (this == obj) {
439                 return true;
440             }
441             if (!(obj instanceof @{importedNames.get("treeNode")})) {
442                 return false;
443             }
444         @if(parentTypeForBuilderName != null) {
445             if (!(obj instanceof @{importedNames.get("instantiable")})) {
446                 return false;
447             }
448             if (!@{importedNames.get("genType")}.class.equals(((@{importedNames.get("instantiable")})obj)
449             .implementedInterface())) {
450                 return false;
451             }
452         }
453             @{importedNames.get("genType")} other = (@{importedNames.get("genType")})obj;
454             @for(property <- properties) {
455                 @if(property.getReturnType.getName.contains("[")) {
456                     if (!@{importedNames.get("arrays")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
457                 } else {
458                     if (!@{importedNames.get("objects")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
459                 }
460                 {
461                     return false;
462                 }
463             }
464             @if(augmentField != null) {
465                 if (getClass() == obj.getClass()) {
466                     // Simple case: we are comparing against self
467                     @{genType.getName}Impl otherImpl = (@{genType.getName}Impl) obj;
468                     if (!@{importedNames.get("objects")}.equals(@{augmentField.getName}, otherImpl.@{augmentField.getName})) {
469                         return false;
470                     }
471                 } @{"else"} {
472                     // Hard case: compare our augments with presence there...
473                     for (@{importedNames.get("map")}.Entry<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e : @{augmentField.getName}.entrySet()) {
474                         if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
475                             return false;
476                         }
477                     }
478                     // .. and give the other one the chance to do the same
479                     if (!obj.equals(this)) {
480                         return false;
481                     }
482                 }
483             }
484             return true;
485         }
486     }
487 }