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