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