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