Binding generator v2 - namespace fix #3
[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
265         public @{genType.getName}Builder set@{toFirstUpper(field.getName)}(final @{field.getReturnType.getFullyQualifiedName} value) {
266         @if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
267             if (value != null) {
268             @if(getRestrictions(field.getReturnType).getRangeConstraints != null && !getRestrictions(field.getReturnType).getRangeConstraints.isEmpty) {
269                 @if(field.getReturnType.isInstanceOf[ConcreteType]) {
270                     @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value")}
271                 } else {
272                     @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value.getValue()")}
273                 }
274             }
275             @if(getRestrictions(field.getReturnType).getLengthConstraints != null && !getRestrictions(field.getReturnType).getLengthConstraints.isEmpty) {
276                 @if(field.getReturnType.isInstanceOf[ConcreteType]) {
277                     @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value")}
278                 } else {
279                     @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value.getValue()")}
280                 }
281             }
282             }
283         }
284             this.@{fieldName(field)} = value;
285             return this;
286         }
287     }
288     @if(augmentField != null) {
289         public @{genType.getName}Builder add@{toFirstUpper(augmentField.getName)}(@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}> augmentationType, @{importedNames.get("augmentFieldReturnType")} augmentation) {
290             if (augmentation == null) {
291                 return remove@{toFirstUpper(augmentField.getName)}(augmentationType);
292             }
293
294             if (!(this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")})) {
295                 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>();
296             }
297
298             this.@{augmentField.getName}.put(augmentationType, augmentation);
299             return this;
300         }
301
302         public @{genType.getName}Builder remove@{toFirstUpper(augmentField.getName)}
303         (@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}> augmentationType) {
304             if (this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")}) {
305                 this.@{augmentField.getName}.remove(augmentationType);
306             }
307             return this;
308         }
309     }
310 }
311
312 @generateGetters(addOverride: Boolean) = {
313     @if(!getterMethods.isEmpty) {
314         @for(property <- getterMethods) {
315             @if(addOverride) {@@Override}
316             @{property}
317         }
318     }
319     @if(augmentField != null) {
320         @@SuppressWarnings("unchecked")
321         @if(addOverride) {@@Override}
322         public <E extends @{importedNames.get("augmentation")}<? super @{genType.getName}>> E get@{toFirstUpper(augmentField.getName)}
323         (@{importedNames.get("class")}<E> augmentationType) {
324             if (augmentationType == null) {
325                 throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
326             }
327             return (E) @{augmentField.getName}.get(augmentationType);
328         }
329     }
330 }
331
332 @generateHashCode() = {
333     @if(!properties.isEmpty || augmentField != null) {
334         private int hash = 0;
335         private volatile boolean hashValid = false;
336
337         @@Override
338         public int hashCode() {
339             if (hashValid) {
340                 return hash;
341             }
342
343             final int prime = 31;
344             int result = 1;
345             @for(property <- properties) {
346                 @if(property.getReturnType.getName.contains("[")) {
347                     result = prime * result + @{importedNames.get("arrays")}.hashCode(@{fieldName(property)});
348                 } else {
349                     result = prime * result + @{importedNames.get("objects")}.hashCode(@{fieldName(property)});
350                 }
351             }
352             @if(augmentField != null) {
353                 result = prime * result + @{importedNames.get("objects")}.hashCode(@{augmentField.getName});
354             }
355
356             hash = result;
357             hashValid = true;
358             return result;
359         }
360     }
361 }
362
363 @generateToString() = {
364     @if(properties != null) {
365         @@Override
366         public @{importedNames.get("string")} toString() {
367             @{importedNames.get("string")} name = "@{genType.getName} [";
368             @{importedNames.get("stringBuilder")} builder = new @{importedNames.get("stringBuilder")}(name);
369             @for((property, index) <- properties.zipWithIndex) {
370                 if (@{fieldName(property)} != null) {
371                     builder.append("@{fieldName(property)}=");
372                     @if(property.getReturnType.getName.contains("[")) {
373                         builder.append(@{importedNames.get("arrays")}.toString(@{fieldName(property)}));
374                     } else {
375                         builder.append(@{fieldName(property)});
376                     }
377                     @if(properties.size() > 1 && index < properties.size()-1){
378                         builder.append(", ");
379                     }
380                 }
381             }
382             @if(augmentField != null) {
383                 @if(!properties.isEmpty()){
384                     final int builderLength = builder.length();
385                     final int builderAdditionalLength = builder.substring(name.length(), builderLength).length();
386                     if (builderAdditionalLength > 2 && !builder.substring(builderLength - 2, builderLength).equals(", ")) {
387                         builder.append(", ");
388                     }
389                 }
390                 builder.append("@{augmentField.getName}=");
391                 builder.append(@{augmentField.getName}.values());
392                 return builder.append(']').toString();
393             } else {
394                 @if(properties.isEmpty()){
395                     return builder.append(']').toString();
396                 } else {
397                     return builder.append(']').toString();
398                 }
399             }
400         }
401     }
402 }
403
404 @generateImplementedMethods() = {
405     @if(childTreeNode) {
406         @@Override
407         public @{importedNames.get("item")}<@{parentTypeForBuilderName}> treeIdentifier() {
408             //TODO implement
409             return null;
410         }
411     }
412
413     @if(augmentField != null) {
414         @@Override
415         public @{importedNames.get("classInstMap")}<@{importedNames.get("augmentation")}<? super @{genType.getName}>>
416         augments() {
417             //TODO implement
418             return null;
419         }
420     }
421 }
422
423 @generateEquals() = {
424     @if(!properties.isEmpty || augmentField != null) {
425         @@Override
426         public boolean equals(@{importedNames.get("object")} obj) {
427             if (this == obj) {
428                 return true;
429             }
430             if (!(obj instanceof @{importedNames.get("treeNode")})) {
431                 return false;
432             }
433         @if(parentTypeForBuilderName != null) {
434             if (!(obj instanceof @{importedNames.get("instantiable")})) {
435                 return false;
436             }
437             if (!@{importedNames.get("genType")}.class.equals(((@{importedNames.get("instantiable")})obj)
438             .implementedInterface())) {
439                 return false;
440             }
441         }
442             @{importedNames.get("genType")} other = (@{importedNames.get("genType")})obj;
443             @for(property <- properties) {
444                 @if(property.getReturnType.getName.contains("[")) {
445                     if (!@{importedNames.get("arrays")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
446                 } else {
447                     if (!@{importedNames.get("objects")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
448                 }
449                 {
450                     return false;
451                 }
452             }
453             @if(augmentField != null) {
454                 if (getClass() == obj.getClass()) {
455                     // Simple case: we are comparing against self
456                     @{genType.getName}Impl otherImpl = (@{genType.getName}Impl) obj;
457                     if (!@{importedNames.get("objects")}.equals(@{augmentField.getName}, otherImpl.@{augmentField.getName})) {
458                         return false;
459                     }
460                 } @{"else"} {
461                     // Hard case: compare our augments with presence there...
462                     for (@{importedNames.get("map")}.Entry<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e : @{augmentField.getName}.entrySet()) {
463                         if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
464                             return false;
465                         }
466                     }
467                     // .. and give the other one the chance to do the same
468                     if (!obj.equals(this)) {
469                         return false;
470                     }
471                 }
472             }
473             return true;
474         }
475     }
476 }