2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
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
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, childTreeNodeIdent: Boolean,
34 keyTypeName: String, instantiable: Boolean)
35 @if(genType != null) {
36 @{wrapToDocumentation(formatDataForJavaDocBuilder(importedNames.get("genType")))}
37 public class @{genType.getName}Builder implements @{getSimpleNameForBuilder} <@{importedNames.get("genType")}> {
39 @generateFields(false)
41 @generateAugmentField(false)
43 @generateConstructorsFromIfcs()
45 @generateCopyConstructor(false)
47 @generateMethodFieldsFrom()
49 @generateGetters(false)
54 public @{genType.getName} build() {
55 return new @{genType.getName}Impl(this);
58 private static final class @{genType.getName}Impl implements @{genType.getName} {
60 @implementedInterfaceGetter()
65 @generateAugmentField(true)
67 @generateCopyConstructor(true)
69 @generateGetters(true)
77 @generateImplementedMethods()
83 * Template method which generates class attributes.
85 * @param isFinal value which specify whether field is|isn't final
86 * @param genType is genType
87 * @return string with class attributes and their types
89 @generateFields(isFinal: Boolean) = {
90 @if(ImportedNamesWithProperties != null) {
91 @for((key, value) <- ImportedNamesWithProperties) {
92 private @if(isFinal) { final}
93 @{value} @{fieldName(key)};
99 * Template method which generates class attributes.
101 * @param boolean value which specify whether field is|isn't final
102 * @return string with class attributes and their types
104 @generateAugmentField(isPrivate: Boolean) = {
105 @if(augmentField != null) {
106 @if(isPrivate) {private }
107 @{importedNames.get("map")}<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>,
108 @{importedNames.get("augmentFieldReturnType")}> @{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
112 @implementedInterfaceGetter() = {
114 public @{importedNames.get("class")}<@{importedNames.get("genType")}> implementedInterface() {
115 return @{importedNames.get("genType")}.class;
120 * Generate default constructor and constructor for every implemented interface from uses statements.
122 @generateConstructorsFromIfcs() = {
123 public @{genType.getName}Builder() {
125 @if(genType.isInstanceOf[GeneratedType] && !genType.isInstanceOf[GeneratedTransferObject]) {
126 @for(impl <- genType.asInstanceOf[GeneratedType].getImplements) {
127 @generateConstructorFromIfc(impl)
132 @generateMethodFieldsFrom() = {
133 @if(genType.isInstanceOf[GeneratedType] && genType.isInstanceOf[GeneratedTypeForBuilder]
134 && !genType.isInstanceOf[GeneratedTransferObject]) {
135 @if(hasImplementsFromUses(genType.asInstanceOf[GeneratedType])) {
137 * Set fields from given grouping argument. Valid argument is instance of one of following types:
139 @for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
140 * <li>@{impl.getFullyQualifiedName}</li>
144 * @@param arg grouping object
145 * @@throws IllegalArgumentException if given argument is none of valid types
148 public void fieldsFrom(@{importedNames.get("treeNode")} arg) {
149 boolean isValidArg = false;
150 @for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
151 @if(impl.isInstanceOf[GeneratedType] && impl.isInstanceOf[GeneratedTypeForBuilder]
152 && !impl.asInstanceOf[GeneratedType].getMethodDefinitions.isEmpty) {
153 if (arg instanceof @{impl.asInstanceOf[GeneratedType].getFullyQualifiedName}) {
154 @if(impl.isInstanceOf[GeneratedType] && impl.isInstanceOf[GeneratedTypeForBuilder]
155 && !impl.isInstanceOf[GeneratedTransferObject]) {
156 @for(getter <- impl.asInstanceOf[GeneratedType].getMethodDefinitions) {
157 this._@{propertyNameFromGetter(getter)} = ((@{impl.asInstanceOf[GeneratedType].getFullyQualifiedName})arg).@{getter.getName}();
165 throw new IllegalArgumentException(
166 "expected one of: @{toListOfNames(getAllIfcs(genType.asInstanceOf[GeneratedType]))} \n" +
176 * Generate constructor with argument of given type.
178 @generateConstructorFromIfc(impl: Type) = {
179 @if(impl.isInstanceOf[GeneratedType] && impl.isInstanceOf[GeneratedTypeForBuilder]) {
180 @if(!impl.asInstanceOf[GeneratedType].getMethodDefinitions.isEmpty) {
181 public @{genType.getName}Builder(
182 @{impl.getFullyQualifiedName} arg) {
183 @{printConstructorPropertySetter(impl)}
186 @for(implTypeImplement <- impl.asInstanceOf[GeneratedType].getImplements) {
187 @generateConstructorFromIfc(implTypeImplement)
192 @printConstructorPropertySetter(implementedIfc: Type) = {
193 @if(implementedIfc.isInstanceOf[GeneratedType] && !implementedIfc.isInstanceOf[GeneratedTransferObject]) {
194 @for(getter <- implementedIfc.asInstanceOf[GeneratedType].getMethodDefinitions) {
195 this._@{propertyNameFromGetter(getter)} = arg.@{getter.getName}();
197 @for(impl <- implementedIfc.asInstanceOf[GeneratedType].getImplements) {
198 @{printConstructorPropertySetter(impl)}
203 @generateImplType() = {
204 @defining(genType.getName + "Impl") {typeImpl => @typeImpl}
207 @generateBuilderType() = {
208 @defining(genType.getName + "Builder") {typeBuilder => @typeBuilder}
211 @generateInnerBuilderType() = {
212 @defining("(" + genType.getName + "Builder base)") {typeInnerBuilder => @typeInnerBuilder}
215 @generateInnerType() = {
216 @defining("(" + genType.getName + " base)") {innerType => @innerType}
219 @generateCopyConstructor(impl: Boolean) = {
220 @if(impl) {private} else {public}
221 @if(impl) {@generateImplType()} else {@generateBuilderType()}
222 @if(impl) {@generateInnerBuilderType()} else {@generateInnerType()}
224 @{copyConstructorHelper}
225 @if(augmentField != null) {
227 switch (base.@{augmentField.getName}.size()) {
229 this.@{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
232 final @{importedNames.get("map")}.Entry<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e = base.@{augmentField.getName}.entrySet().iterator().next();
233 this.@{augmentField.getName} = @{importedNames.get("collections")}.<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> singletonMap(e.getKey(), e.getValue());
236 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(base.@{augmentField.getName});
239 if (base instanceof @{genType.getName}Impl) {
240 @{genType.getName}Impl impl = (@{genType.getName}Impl) base;
241 if (!impl.@{augmentField.getName}.isEmpty()) {
242 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(impl.@{augmentField.getName});
244 } @{"else"} if (base instanceof @{importedNames.get("augmentationHolder")}) {
245 @@SuppressWarnings("unchecked")
246 @{importedNames.get("augmentationHolder")}<@{importedNames.get("genType")}> casted =(@{importedNames.get("augmentationHolder")}<@{importedNames.get("genType")}>) base;
247 if (!casted.augmentations().isEmpty()) {
248 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(casted.augmentations());
257 @generateSetters() = {
258 @for(field <- properties) {
259 @if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
260 @if(getRestrictions(field.getReturnType).getRangeConstraint.isPresent) {
261 @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeChecker(toFirstUpper(field.getName),
262 getRestrictions(field.getReturnType).getRangeConstraint.get)}
264 @if(getRestrictions(field.getReturnType).getLengthConstraint.isPresent) {
265 @{LengthGenerator.generateLengthChecker(fieldName(field), field.getReturnType,
266 getRestrictions(field.getReturnType).getLengthConstraint.get)}
270 public @{genType.getName}Builder set@{toFirstUpper(field.getName)}(final @{field.getReturnType.getFullyQualifiedName} value) {
271 @if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
273 @if(getRestrictions(field.getReturnType).getRangeConstraint.isPresent) {
274 @if(field.getReturnType.isInstanceOf[ConcreteType]) {
275 @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value")}
277 @{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value.getValue()")}
280 @if(getRestrictions(field.getReturnType).getLengthConstraint.isPresent) {
281 @if(field.getReturnType.isInstanceOf[ConcreteType]) {
282 @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value")}
284 @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value.getValue()")}
289 this.@{fieldName(field)} = value;
293 @if(augmentField != null) {
294 public @{genType.getName}Builder add@{toFirstUpper(augmentField.getName)}(@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}> augmentationType, @{importedNames.get("augmentFieldReturnType")} augmentation) {
295 if (augmentation == null) {
296 return remove@{toFirstUpper(augmentField.getName)}(augmentationType);
299 if (!(this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")})) {
300 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>();
303 this.@{augmentField.getName}.put(augmentationType, augmentation);
307 public @{genType.getName}Builder remove@{toFirstUpper(augmentField.getName)}
308 (@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}> augmentationType) {
309 if (this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")}) {
310 this.@{augmentField.getName}.remove(augmentationType);
317 @generateGetters(addOverride: Boolean) = {
318 @if(!getterMethods.isEmpty) {
319 @for(property <- getterMethods) {
320 @if(addOverride) {@@Override}
324 @if(augmentField != null) {
325 @@SuppressWarnings("unchecked")
326 @if(addOverride) {@@Override}
327 public <E extends @{importedNames.get("augmentation")}<? super @{genType.getName}>> E get@{toFirstUpper(augmentField.getName)}
328 (@{importedNames.get("class")}<E> augmentationType) {
329 if (augmentationType == null) {
330 throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
332 return (E) @{augmentField.getName}.get(augmentationType);
337 @generateHashCode() = {
338 @if(!properties.isEmpty || augmentField != null) {
339 private int hash = 0;
340 private volatile boolean hashValid = false;
343 public int hashCode() {
348 final int prime = 31;
350 @for(property <- properties) {
351 @if(property.getReturnType.getName.contains("[")) {
352 result = prime * result + @{importedNames.get("arrays")}.hashCode(@{fieldName(property)});
354 result = prime * result + @{importedNames.get("objects")}.hashCode(@{fieldName(property)});
357 @if(augmentField != null) {
358 result = prime * result + @{importedNames.get("objects")}.hashCode(@{augmentField.getName});
368 @generateToString() = {
369 @if(properties != null) {
371 public @{importedNames.get("string")} toString() {
372 @{importedNames.get("string")} name = "@{genType.getName} [";
373 @{importedNames.get("stringBuilder")} builder = new @{importedNames.get("stringBuilder")}(name);
374 @for((property, index) <- properties.zipWithIndex) {
375 if (@{fieldName(property)} != null) {
376 builder.append("@{fieldName(property)}=");
377 @if(property.getReturnType.getName.contains("[")) {
378 builder.append(@{importedNames.get("arrays")}.toString(@{fieldName(property)}));
380 builder.append(@{fieldName(property)});
382 @if(properties.size() > 1 && index < properties.size()-1){
383 builder.append(", ");
387 @if(augmentField != null) {
388 @if(!properties.isEmpty()){
389 final int builderLength = builder.length();
390 final int builderAdditionalLength = builder.substring(name.length(), builderLength).length();
391 if (builderAdditionalLength > 2 && !builder.substring(builderLength - 2, builderLength).equals(", ")) {
392 builder.append(", ");
395 builder.append("@{augmentField.getName}=");
396 builder.append(@{augmentField.getName}.values());
397 return builder.append(']').toString();
399 @if(properties.isEmpty()){
400 return builder.append(']').toString();
402 return builder.append(']').toString();
409 @generateImplementedMethods() = {
410 @if(childTreeNodeIdent) {
412 public @{importedNames.get("identifiableItem")}<@{genType.getName()}, @{keyTypeName}> treeIdentifier() {
413 return new @{importedNames.get("identifiableItem")}(@{importedNames.get("genType")}.class,_identifier);
418 public @{importedNames.get("item")}<@{genType.getName()}> treeIdentifier() {
419 return new @{importedNames.get("item")}(@{importedNames.get("genType")}.class);
424 @if(augmentField != null) {
426 public @{importedNames.get("classInstMap")}<@{importedNames.get("augmentation")}<? super @{genType.getName}>>
434 @generateEquals() = {
435 @if(!properties.isEmpty || augmentField != null) {
437 public boolean equals(@{importedNames.get("object")} obj) {
441 if (!(obj instanceof @{importedNames.get("treeNode")})) {
444 @if(parentTypeForBuilderName != null) {
445 if (!(obj instanceof @{importedNames.get("instantiable")})) {
448 if (!@{importedNames.get("genType")}.class.equals(((@{importedNames.get("instantiable")})obj)
449 .implementedInterface())) {
453 @{importedNames.get("genType")} other = (@{importedNames.get("genType")})obj;
454 @for(property <- properties) {
455 @if(property.getReturnType.getName.contains("[")) {
456 if (!@{importedNames.get("arrays")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
458 if (!@{importedNames.get("objects")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
464 @if(augmentField != null) {
465 if (getClass() == obj.getClass()) {
466 // Simple case: we are comparing against self
467 @{genType.getName}Impl otherImpl = (@{genType.getName}Impl) obj;
468 if (!@{importedNames.get("objects")}.equals(@{augmentField.getName}, otherImpl.@{augmentField.getName})) {
472 // Hard case: compare our augments with presence there...
473 for (@{importedNames.get("map")}.Entry<@{importedNames.get("class")}<? extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e : @{augmentField.getName}.entrySet()) {
474 if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
478 // .. and give the other one the chance to do the same
479 if (!obj.equals(this)) {