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