Binding v2 - Fix setter constant naming
[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     } else {
316         public @{genType.getName}Builder set@{toFirstUpper(field.getName)}(final @{ImportedNamesWithProperties.get(field)} value) {
317             @if(!actualType.isInstanceOf[GeneratedType] && getRestrictions(actualType) != null) {
318                 if (value != null) {
319                     @checkArgument(field, actualType)
320                 }
321             }
322             this.@{fieldName(field)} = value;
323             return this;
324         }
325     }
326 }
327
328 @checkArgument(field: GeneratedProperty, actualType: Type) = {
329     @if(getRestrictions(actualType).getRangeConstraint.isPresent) {
330         @if(actualType.isInstanceOf[ConcreteType]) {
331             @{AbstractRangeGenerator.forType(actualType).generateRangeCheckerCall(toFirstUpper(field.getName), "value")}
332         } else {
333             @{AbstractRangeGenerator.forType(actualType).generateRangeCheckerCall(toFirstUpper(field.getName), "value.getValue()")}
334         }
335     }
336     @if(getRestrictions(actualType).getLengthConstraint.isPresent) {
337         @if(actualType.isInstanceOf[ConcreteType]) {
338             @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value")}
339         } else {
340             @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value.getValue()")}
341         }
342     }
343     @for(currentConstant <- genType.getConstantDefinitions) {
344         @defining(fieldName(field)) { suffix =>
345         @if(currentConstant.getName.startsWith(BindingMapping.PATTERN_CONSTANT_NAME)
346                 && suffix.equals(currentConstant.getName.substring(BindingMapping.PATTERN_CONSTANT_NAME.length))) {
347             @{importedNames.get("codeHelpers")}.checkPattern(value, @{BindingMapping.MEMBER_PATTERN_LIST}@{suffix}, @{BindingMapping.MEMBER_REGEX_LIST}@{suffix});
348         }
349         }
350     }
351 }
352
353 @generateGetters(addOverride: Boolean) = {
354     @if(!getterMethods.isEmpty) {
355         @for(property <- getterMethods) {
356             @if(addOverride) {@@Override}
357             @{property}
358         }
359     }
360     @if(augmentField != null) {
361         @@SuppressWarnings("unchecked")
362         @if(addOverride) {@@Override}
363         public <E extends @{importedNames.get("augmentation")}<? super @{genType.getName}>> E get@{toFirstUpper(augmentField.getName)}
364         (@{importedNames.get("class")}<E> augmentationType) {
365             return (E) @{augmentField.getName}.get(@{importedNames.get("codeHelpers")}.nonNullValue(augmentationType, "augmentationType"));
366         }
367     }
368 }
369
370 @generateHashCode() = {
371     @if(!properties.isEmpty || augmentField != null) {
372         private int hash = 0;
373         private volatile boolean hashValid = false;
374
375         @@Override
376         public int hashCode() {
377             if (hashValid) {
378                 return hash;
379             }
380
381             final int prime = 31;
382             int result = 1;
383             @for(property <- properties) {
384                 @if(property.getReturnType.getName.contains("[")) {
385                     result = prime * result + @{importedNames.get("arrays")}.hashCode(@{fieldName(property)});
386                 } else {
387                     result = prime * result + @{importedNames.get("objects")}.hashCode(@{fieldName(property)});
388                 }
389             }
390             @if(augmentField != null) {
391                 result = prime * result + @{importedNames.get("objects")}.hashCode(@{augmentField.getName});
392             }
393
394             hash = result;
395             hashValid = true;
396             return result;
397         }
398     }
399 }
400
401 @generateToString() = {
402     @if(properties != null) {
403         @@Override
404         public @{importedNames.get("string")} toString() {
405             @{importedNames.get("string")} name = "@{genType.getName} [";
406             @{importedNames.get("stringBuilder")} builder = new @{importedNames.get("stringBuilder")}(name);
407             @for((property, index) <- properties.zipWithIndex) {
408                 if (@{fieldName(property)} != null) {
409                     builder.append("@{fieldName(property)}=");
410                     @if(property.getReturnType.getName.contains("[")) {
411                         builder.append(@{importedNames.get("arrays")}.toString(@{fieldName(property)}));
412                     } else {
413                         builder.append(@{fieldName(property)});
414                     }
415                     @if(properties.size() > 1 && index < properties.size()-1){
416                         builder.append(", ");
417                     }
418                 }
419             }
420             @if(augmentField != null) {
421                 @if(!properties.isEmpty()){
422                     final int builderLength = builder.length();
423                     final int builderAdditionalLength = builder.substring(name.length(), builderLength).length();
424                     if (builderAdditionalLength > 2 && !builder.substring(builderLength - 2, builderLength).equals(", ")) {
425                         builder.append(", ");
426                     }
427                 }
428                 builder.append("@{augmentField.getName}=");
429                 builder.append(@{augmentField.getName}.values());
430                 return builder.append(']').toString();
431             } else {
432                 @if(properties.isEmpty()){
433                     return builder.append(']').toString();
434                 } else {
435                     return builder.append(']').toString();
436                 }
437             }
438         }
439     }
440 }
441
442 @generateImplementedMethods() = {
443     @if(childTreeNodeIdent) {
444         @@Override
445         public @{importedNames.get("identifiableItem")}<@{genType.getName()}, @{keyTypeName}> treeIdentifier() {
446             return new @{importedNames.get("identifiableItem")}(@{importedNames.get("genType")}.class,_identifier);
447         }
448     } else {
449       @if(childTreeNode) {
450           @@Override
451           public @{importedNames.get("item")}<@{genType.getName()}> treeIdentifier() {
452                return new @{importedNames.get("item")}(@{importedNames.get("genType")}.class);
453           }
454       }
455     }
456
457     @if(augmentField != null) {
458         @@Override
459         public @{importedNames.get("classInstMap")}<@{importedNames.get("augmentation")}<? super @{genType.getName}>>
460         augments() {
461             //TODO implement
462             return null;
463         }
464     }
465 }
466
467 @generateEquals() = {
468     @if(!properties.isEmpty || augmentField != null) {
469         @@Override
470         public boolean equals(@{importedNames.get("object")} obj) {
471             if (this == obj) {
472                 return true;
473             }
474             if (!(obj instanceof @{importedNames.get("treeNode")})) {
475                 return false;
476             }
477         @if(parentTypeForBuilderName != null) {
478             if (!(obj instanceof @{importedNames.get("instantiable")})) {
479                 return false;
480             }
481             if (!@{importedNames.get("genType")}.class.equals(((@{importedNames.get("instantiable")})obj)
482             .implementedInterface())) {
483                 return false;
484             }
485         }
486             @{importedNames.get("genType")} other = (@{importedNames.get("genType")})obj;
487             @for(property <- properties) {
488                 @if(property.getReturnType.getName.contains("[")) {
489                     if (!@{importedNames.get("arrays")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
490                 } else {
491                     if (!@{importedNames.get("objects")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
492                 }
493                 {
494                     return false;
495                 }
496             }
497             @if(augmentField != null) {
498                 if (getClass() == obj.getClass()) {
499                     // Simple case: we are comparing against self
500                     @{genType.getName}Impl otherImpl = (@{genType.getName}Impl) obj;
501                     if (!@{importedNames.get("objects")}.equals(@{augmentField.getName}, otherImpl.@{augmentField.getName})) {
502                         return false;
503                     }
504                 } @{"else"} {
505                     // Hard case: compare our augments with presence there...
506                     for (@{importedNames.get("map")}.Entry<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e : @{augmentField.getName}.entrySet()) {
507                         if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
508                             return false;
509                         }
510                     }
511                     // .. and give the other one the chance to do the same
512                     if (!obj.equals(this)) {
513                         return false;
514                     }
515                 }
516             }
517             return true;
518         }
519     }
520 }