Make Builders sensitive to @Deprecated annotations
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / AbstractBuilderTemplate.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.spec.naming.BindingMapping.AUGMENTATION_FIELD
11
12 import com.google.common.base.MoreObjects
13 import java.util.ArrayList
14 import java.util.Collection
15 import java.util.Collections
16 import java.util.Comparator
17 import java.util.List
18 import java.util.Map
19 import java.util.Set
20 import org.opendaylight.mdsal.binding.model.api.AnnotationType
21 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
22 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
23 import org.opendaylight.mdsal.binding.model.api.GeneratedType
24 import org.opendaylight.mdsal.binding.model.api.JavaTypeName
25 import org.opendaylight.mdsal.binding.model.api.Type
26 import org.opendaylight.mdsal.binding.model.util.Types
27 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
28 import org.opendaylight.yangtools.yang.binding.CodeHelpers
29 import org.opendaylight.yangtools.yang.binding.Identifiable
30
31 abstract class AbstractBuilderTemplate extends BaseTemplate {
32     static val Comparator<GeneratedProperty> KEY_PROPS_COMPARATOR = [ p1, p2 | return p1.name.compareTo(p2.name) ]
33
34     protected static val DEPRECATED = JavaTypeName.create(Deprecated);
35
36     /**
37      * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME.
38      */
39     protected val Type augmentType
40
41     /**
42      * Set of class attributes (fields) which are derived from the getter methods names.
43      */
44     protected val Set<GeneratedProperty> properties
45
46     /**
47      * GeneratedType for key type, null if this type does not have a key.
48      */
49     protected val Type keyType
50
51     protected val GeneratedType targetType;
52
53     new(AbstractJavaGeneratedType javaType, GeneratedType type, GeneratedType targetType,
54             Set<GeneratedProperty> properties, Type augmentType, Type keyType) {
55         super(javaType, type)
56         this.targetType = targetType
57         this.properties = properties
58         this.augmentType = augmentType
59         this.keyType = keyType
60     }
61
62     new(GeneratedType type, GeneratedType targetType, Set<GeneratedProperty> properties, Type augmentType,
63             Type keyType) {
64         super(type)
65         this.targetType = targetType
66         this.properties = properties
67         this.augmentType = augmentType
68         this.keyType = keyType
69     }
70
71     /**
72      * Template method which generates class attributes.
73      *
74      * @param makeFinal value which specify whether field is|isn't final
75      * @return string with class attributes and their types
76      */
77     def protected final generateFields(boolean makeFinal) '''
78         «IF properties !== null»
79             «FOR f : properties»
80                 private«IF makeFinal» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
81             «ENDFOR»
82         «ENDIF»
83         «IF keyType !== null»
84             private«IF makeFinal» final«ENDIF» «keyType.importedName» key;
85         «ENDIF»
86     '''
87
88     def protected final generateAugmentField() {
89         val augmentTypeRef = augmentType.importedName
90         return '''
91            «Map.importedName»<«Class.importedName»<? extends «augmentTypeRef»>, «augmentTypeRef»> «AUGMENTATION_FIELD» = «Collections.importedName».emptyMap();
92         '''
93     }
94
95     override generateToString(Collection<GeneratedProperty> properties) '''
96         «IF properties !== null»
97             @«Override.importedName»
98             public «String.importedName» toString() {
99                 final «MoreObjects.importedName».ToStringHelper helper = «MoreObjects.importedName».toStringHelper("«targetType.name»");
100                 «FOR property : properties»
101                     «CodeHelpers.importedName».appendValue(helper, "«property.fieldName»", «property.fieldName»);
102                 «ENDFOR»
103                 «IF augmentType !== null»
104                     «CodeHelpers.importedName».appendValue(helper, "«AUGMENTATION_FIELD»", augmentations().values());
105                 «ENDIF»
106                 return helper.toString();
107             }
108         «ENDIF»
109     '''
110
111     /**
112      * Template method which generate getter methods for IMPL class.
113      *
114      * @return string with getter methods
115      */
116     def final generateGetters(boolean addOverride) '''
117         «IF keyType !== null»
118             «IF addOverride»@«Override.importedName»«ENDIF»
119             public «keyType.importedName» «BindingMapping.IDENTIFIABLE_KEY_NAME»() {
120                 return key;
121             }
122
123         «ENDIF»
124         «IF !properties.empty»
125             «FOR field : properties SEPARATOR '\n'»
126                 «IF addOverride»@«Override.importedName»«ENDIF»
127                 «field.getterMethod»
128             «ENDFOR»
129         «ENDIF»
130     '''
131
132     def protected final CharSequence generateCopyConstructor(Type fromType, Type implType) '''
133         «type.name»(«fromType.importedName» base) {
134             «IF augmentType !== null»
135                 «generateCopyAugmentation(implType)»
136             «ENDIF»
137             «val allProps = new ArrayList(properties)»
138             «val isList = implementsIfc(targetType, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), targetType))»
139             «IF isList && keyType !== null»
140                 «val keyProps = new ArrayList((keyType as GeneratedTransferObject).properties)»
141                 «keyProps.sort(KEY_PROPS_COMPARATOR)»
142                 «FOR field : keyProps»
143                     «removeProperty(allProps, field.name)»
144                 «ENDFOR»
145                 «generateCopyKeys(keyProps)»
146             «ENDIF»
147             «FOR field : allProps»
148                 this.«field.fieldName» = base.«field.getterMethodName»();
149             «ENDFOR»
150         }
151     '''
152
153     def protected final CharSequence generateDeprecatedAnnotation(List<AnnotationType> annotations) {
154         var AnnotationType found = annotations.findDeprecatedAnnotation
155         if (found === null) {
156             return ""
157         }
158         return generateDeprecatedAnnotation(found)
159     }
160
161     def protected abstract CharSequence generateCopyKeys(List<GeneratedProperty> keyProps)
162
163     def protected abstract CharSequence generateCopyAugmentation(Type implType)
164
165     def protected abstract CharSequence generateDeprecatedAnnotation(AnnotationType ann)
166
167     private def boolean implementsIfc(GeneratedType type, Type impl) {
168         for (Type ifc : type.implements) {
169             if (ifc.equals(impl)) {
170                 return true;
171             }
172         }
173         return false;
174     }
175
176     private def void removeProperty(Collection<GeneratedProperty> props, String name) {
177         var GeneratedProperty toRemove = null
178         for (p : props) {
179             if (p.name.equals(name)) {
180                 toRemove = p;
181             }
182         }
183         if (toRemove !== null) {
184             props.remove(toRemove);
185         }
186     }
187
188     private static def findDeprecatedAnnotation(List<AnnotationType> annotations) {
189         if (annotations !== null) {
190             for (annotation : annotations) {
191                 if (DEPRECATED.equals(annotation.identifier)) {
192                     return annotation
193                 }
194             }
195         }
196         return null
197     }
198 }