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