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