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.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
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")}> {
42 @generateFields(false)
46 @generateAugmentField(false)
48 @generateConstructorsFromIfcs()
50 @generateCopyConstructor(false)
52 @generateMethodFieldsFrom()
54 @generateGetters(false)
59 public @{genType.getName} build() {
60 return new @{genType.getName}Impl(this);
63 private static final class @{genType.getName}Impl implements @{genType.getName} {
65 @implementedInterfaceGetter()
70 @generateAugmentField(true)
72 @generateCopyConstructor(true)
74 @generateGetters(true)
82 @generateImplementedMethods()
88 * Template method which generates class attributes.
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
94 @generateFields(isFinal: Boolean) = {
95 @if(ImportedNamesWithProperties != null) {
96 @for((key, value) <- ImportedNamesWithProperties) {
97 private @if(isFinal) { final}
98 @{value} @{fieldName(key)};
104 * Template method which generates class attributes.
106 * @param boolean value which specify whether field is|isn't final
107 * @return string with class attributes and their types
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();
117 @implementedInterfaceGetter() = {
119 public @{importedNames.get("class")}<@{importedNames.get("genType")}> implementedInterface() {
120 return @{importedNames.get("genType")}.class;
125 * Generate default constructor and constructor for every implemented interface from uses statements.
127 @generateConstructorsFromIfcs() = {
128 public @{genType.getName}Builder() {
130 @if(genType.isInstanceOf[GeneratedType] && !genType.isInstanceOf[GeneratedTransferObject]) {
131 @for(impl <- genType.asInstanceOf[GeneratedType].getImplements) {
132 @generateConstructorFromIfc(impl)
137 @generateMethodFieldsFrom() = {
138 @if(genType.isInstanceOf[GeneratedType] && genType.isInstanceOf[GeneratedTypeForBuilder]
139 && !genType.isInstanceOf[GeneratedTransferObject]) {
140 @if(hasImplementsFromUses(genType.asInstanceOf[GeneratedType])) {
142 * Set fields from given grouping argument. Valid argument is instance of one of following types:
144 @for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
145 * <li>@{impl.getFullyQualifiedName}</li>
149 * @@param arg grouping object
150 * @@throws IllegalArgumentException if given argument is none of valid types
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}();
170 @{importedNames.get("codeHelpers")}.validValue(isValidArg, arg, "@{toListOfNames(getAllIfcs(genType.asInstanceOf[GeneratedType]))}");
177 * Generate constructor with argument of given type.
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)}
187 @for(implTypeImplement <- impl.asInstanceOf[GeneratedType].getImplements) {
188 @generateConstructorFromIfc(implTypeImplement)
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}();
198 @for(impl <- implementedIfc.asInstanceOf[GeneratedType].getImplements) {
199 @{printConstructorPropertySetter(impl)}
204 @generateImplType() = {
205 @defining(genType.getName + "Impl") {typeImpl => @typeImpl}
208 @generateBuilderType() = {
209 @defining(genType.getName + "Builder") {typeBuilder => @typeBuilder}
212 @generateInnerBuilderType() = {
213 @defining("(" + genType.getName + "Builder base)") {typeInnerBuilder => @typeInnerBuilder}
216 @generateInnerType() = {
217 @defining("(" + genType.getName + " base)") {innerType => @innerType}
220 @generateCopyConstructor(impl: Boolean) = {
221 @if(impl) {private} else {public}
222 @if(impl) {@generateImplType()} else {@generateBuilderType()}
223 @if(impl) {@generateInnerBuilderType()} else {@generateInnerType()}
225 @{copyConstructorHelper}
226 @if(augmentField != null) {
228 switch (base.@{augmentField.getName}.size()) {
230 this.@{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
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());
237 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(base.@{augmentField.getName});
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});
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());
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)
263 @generateSetter(field, field.getReturnType, false)
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);
273 if (!(this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")})) {
274 this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>();
277 this.@{augmentField.getName}.put(augmentationType, augmentation);
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);
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)}
297 @if(getRestrictions(actualType).getLengthConstraint.isPresent) {
298 @{LengthGenerator.generateLengthChecker(fieldName(field), actualType,
299 getRestrictions(actualType).getLengthConstraint.get)}
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)
312 this.@{fieldName(field)} = values;
316 @generateListMethods(field, actualType)
318 public @{genType.getName}Builder set@{toFirstUpper(field.getName)}(final @{ImportedNamesWithProperties.get(field)} value) {
319 @if(!actualType.isInstanceOf[GeneratedType] && getRestrictions(actualType) != null) {
321 @checkArgument(field, actualType)
324 this.@{fieldName(field)} = value;
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) {
334 @checkArgument(field, actualType)
338 if (this.@{fieldName(field)} == null) {
339 this.@{fieldName(field)} = new @{importedNames.get("arrayList")}<>();
342 this.@{fieldName(field)}.add(value);
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);
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")}
360 @{AbstractRangeGenerator.forType(actualType).generateRangeCheckerCall(toFirstUpper(field.getName), "value.getValue()")}
363 @if(getRestrictions(actualType).getLengthConstraint.isPresent) {
364 @if(actualType.isInstanceOf[ConcreteType]) {
365 @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value")}
367 @{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value.getValue()")}
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});
380 @generateGetters(addOverride: Boolean) = {
381 @if(!getterMethods.isEmpty) {
382 @for(property <- getterMethods) {
383 @if(addOverride) {@@Override}
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"));
397 @generateHashCode() = {
398 @if(!properties.isEmpty || augmentField != null) {
399 private int hash = 0;
400 private volatile boolean hashValid = false;
403 public int hashCode() {
408 final int prime = 31;
410 @for(property <- properties) {
411 @if(property.getReturnType.getName.contains("[")) {
412 result = prime * result + @{importedNames.get("arrays")}.hashCode(@{fieldName(property)});
414 result = prime * result + @{importedNames.get("objects")}.hashCode(@{fieldName(property)});
417 @if(augmentField != null) {
418 result = prime * result + @{importedNames.get("objects")}.hashCode(@{augmentField.getName});
428 @generateToString() = {
429 @if(properties != null) {
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)}));
440 builder.append(@{fieldName(property)});
442 @if(properties.size() > 1 && index < properties.size()-1){
443 builder.append(", ");
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(", ");
455 builder.append("@{augmentField.getName}=");
456 builder.append(@{augmentField.getName}.values());
457 return builder.append(']').toString();
459 @if(properties.isEmpty()){
460 return builder.append(']').toString();
462 return builder.append(']').toString();
469 @generateImplementedMethods() = {
470 @if(childTreeNodeIdent) {
472 public @{importedNames.get("identifiableItem")}<@{genType.getName()}, @{keyTypeName}> treeIdentifier() {
473 return new @{importedNames.get("identifiableItem")}(@{importedNames.get("genType")}.class,_identifier);
478 public @{importedNames.get("item")}<@{genType.getName()}> treeIdentifier() {
479 return new @{importedNames.get("item")}(@{importedNames.get("genType")}.class);
484 @if(augmentField != null) {
486 public @{importedNames.get("classInstMap")}<@{importedNames.get("augmentation")}<? super @{genType.getName}>>
494 @generateEquals() = {
495 @if(!properties.isEmpty || augmentField != null) {
497 public boolean equals(@{importedNames.get("object")} obj) {
501 if (!(obj instanceof @{importedNames.get("treeNode")})) {
504 @if(parentTypeForBuilderName != null) {
505 if (!(obj instanceof @{importedNames.get("instantiable")})) {
508 if (!@{importedNames.get("genType")}.class.equals(((@{importedNames.get("instantiable")})obj)
509 .implementedInterface())) {
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)}()))
518 if (!@{importedNames.get("objects")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
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})) {
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()))) {
538 // .. and give the other one the chance to do the same
539 if (!obj.equals(this)) {