Specialize relative leafref types during instantiation
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / BuilderImplTemplate.xtend
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 package org.opendaylight.mdsal.binding.java.api.generator
9
10 import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
11 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
12 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_EQUALS_NAME
13 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_HASHCODE_NAME
14 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_TO_STRING_NAME
15
16 import java.util.Collection
17 import java.util.List
18 import java.util.Optional
19 import org.opendaylight.mdsal.binding.model.api.AnnotationType
20 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
21 import org.opendaylight.mdsal.binding.model.api.GeneratedType
22 import org.opendaylight.mdsal.binding.model.api.MethodSignature
23 import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics
24 import org.opendaylight.mdsal.binding.model.api.Type
25 import org.opendaylight.mdsal.binding.model.util.Types
26 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
27 import org.opendaylight.yangtools.yang.binding.AbstractAugmentable
28
29 class BuilderImplTemplate extends AbstractBuilderTemplate {
30     val BuilderTemplate builder;
31
32     new(BuilderTemplate builder, GeneratedType type) {
33         super(builder.javaType.getEnclosedType(type.identifier), type, builder.targetType, builder.properties,
34             builder.augmentType, builder.keyType)
35         this.builder = builder
36     }
37
38     override body() '''
39         «targetType.annotations.generateDeprecatedAnnotation»
40         private static final class «type.name»
41             «val impIface = targetType.importedName»
42             «IF augmentType !== null»
43                 extends «AbstractAugmentable.importedName»<«impIface»>
44             «ENDIF»
45             implements «impIface» {
46
47             «generateFields(true)»
48
49             «generateCopyConstructor(builder.type, type)»
50
51             «generateGetters()»
52
53             «generateHashCode()»
54
55             «generateEquals()»
56
57             «generateToString()»
58         }
59     '''
60
61     override generateDeprecatedAnnotation(AnnotationType ann) {
62         return generateAnnotation(ann)
63     }
64
65     def private generateGetters() '''
66         «IF keyType !== null»
67             @«OVERRIDE.importedName»
68             public «keyType.importedName» «BindingMapping.IDENTIFIABLE_KEY_NAME»() {
69                 return key;
70             }
71
72         «ENDIF»
73         «IF !properties.empty»
74             «FOR field : properties SEPARATOR '\n'»
75                 «field.getterMethod»
76             «ENDFOR»
77         «ENDIF»
78     '''
79
80     private static def Optional<MethodSignature> findGetter(GeneratedType implType, String getterName) {
81         val getter = getterByName(implType.nonDefaultMethods, getterName);
82         if (getter.isPresent) {
83             return getter;
84         }
85         for (ifc : implType.implements) {
86             if (ifc instanceof GeneratedType) {
87                 val getterImpl = findGetter(ifc, getterName)
88                 if (getterImpl.isPresent) {
89                     return (getterImpl)
90                 }
91             }
92         }
93         return Optional.empty
94     }
95
96     override getterMethod(GeneratedProperty field) '''
97         @«OVERRIDE.importedName»
98         public «field.returnType.importedName» «field.getterMethodName»() {
99             «val fieldName = field.fieldName»
100             «IF field.returnType.name.endsWith("[]")»
101                 return «fieldName» == null ? null : «fieldName».clone();
102             «ELSE»
103                 return «fieldName»;
104             «ENDIF»
105         }
106     '''
107
108     package def findGetter(String getterName) {
109         val ownGetter = getterByName(type.nonDefaultMethods, getterName);
110         if (ownGetter.isPresent) {
111             return ownGetter.get;
112         }
113         for (ifc : type.implements) {
114             if (ifc instanceof GeneratedType) {
115                 val getter = findGetter(ifc, getterName)
116                 if (getter.isPresent) {
117                     return (getter.get)
118                 }
119             }
120         }
121         throw new IllegalStateException(
122                 String.format("%s should be present in %s type or in one of its ancestors as getter",
123                         getterName.propertyNameFromGetter, type));
124     }
125
126     /**
127      * Template method which generates the method <code>hashCode()</code>.
128      *
129      * @return string with the <code>hashCode()</code> method definition in JAVA format
130      */
131     def protected generateHashCode() '''
132         «IF !properties.empty || augmentType !== null»
133             private int hash = 0;
134             private volatile boolean hashValid = false;
135
136             @«OVERRIDE.importedName»
137             public int hashCode() {
138                 if (hashValid) {
139                     return hash;
140                 }
141
142                 final int result = «targetType.importedName».«BINDING_HASHCODE_NAME»(this);
143                 hash = result;
144                 hashValid = true;
145                 return result;
146             }
147         «ENDIF»
148     '''
149
150     /**
151      * Template method which generates the method <code>equals()</code>.
152      *
153      * @return string with the <code>equals()</code> method definition in JAVA format
154      */
155     def protected generateEquals() '''
156         «IF !properties.empty || augmentType !== null»
157             @«OVERRIDE.importedName»
158             public boolean equals(«Types.objectType().importedName» obj) {
159                 return «targetType.importedName».«BINDING_EQUALS_NAME»(this, obj);
160             }
161         «ENDIF»
162     '''
163
164     /**
165      * Template method which generates the method <code>toString()</code>.
166      *
167      * @return string with the <code>toString()</code> method definition in JAVA format
168      */
169     def protected generateToString() '''
170         @«OVERRIDE.importedName»
171         public «STRING.importedName» toString() {
172             return «targetType.importedName».«BINDING_TO_STRING_NAME»(this);
173         }
174     '''
175
176     override protected generateCopyKeys(List<GeneratedProperty> keyProps) '''
177         if (base.«BindingMapping.IDENTIFIABLE_KEY_NAME»() != null) {
178             this.key = base.«BindingMapping.IDENTIFIABLE_KEY_NAME»();
179         } else {
180             this.key = new «keyType.importedName»(«FOR keyProp : keyProps SEPARATOR ", "»base.«keyProp.getterMethodName»()«ENDFOR»);
181         }
182         «FOR field : keyProps»
183             this.«field.fieldName» = key.«field.getterMethodName»();
184         «ENDFOR»
185     '''
186
187     override protected CharSequence generateCopyNonKeys(Collection<BuilderGeneratedProperty> props) '''
188         «FOR field : props»
189             «IF field.mechanics === ValueMechanics.NULLIFY_EMPTY»
190                 this.«field.fieldName» = «CODEHELPERS.importedName».emptyToNull(base.«field.getterName»());
191             «ELSE»
192                 this.«field.fieldName» = base.«field.getterName»();
193             «ENDIF»
194         «ENDFOR»
195     '''
196
197     override protected generateCopyAugmentation(Type implType) '''
198         super(base.«AUGMENTATION_FIELD»);
199     '''
200 }