Fixed performance issues with implementation of BA-to-BI mapping
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / connect / dom / BindingMapping.xtend
1 package org.opendaylight.controller.sal.binding.impl.connect.dom
2
3 import org.opendaylight.yangtools.yang.common.QName
4 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext
5 import java.util.List
6 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
7 import org.opendaylight.yangtools.sal.binding.model.api.Type
8 import org.opendaylight.yangtools.yang.model.api.SchemaNode
9 import java.util.Map
10 import org.opendaylight.yangtools.yang.model.api.SchemaPath
11 import org.opendaylight.yangtools.yang.model.api.SchemaContext
12 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
13 import org.opendaylight.yangtools.binding.generator.util.Types
14 import java.util.HashMap
15 import org.opendaylight.yangtools.yang.data.api.CompositeNode
16 import org.opendaylight.yangtools.yang.binding.DataContainer
17 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
18 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
19 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
20 import java.util.Collections
21 import java.util.ArrayList
22 import org.opendaylight.yangtools.yang.data.api.Node
23 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
24 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
25 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
27 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
28 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
29 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
30 import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
31 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
32 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
33 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
34 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition
35 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
37 import org.opendaylight.yangtools.yang.binding.DataObject
38 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
41 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
42 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
43 import org.opendaylight.yangtools.yang.model.util.ExtendedType
44 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
45 import com.google.common.collect.FluentIterable
46 import org.opendaylight.yangtools.yang.data.api.SimpleNode
47 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
48 import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
49 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
50 import com.google.common.collect.HashMultimap
51 import com.google.common.collect.ArrayListMultimap
52 import com.google.common.collect.Multimap
53 import java.util.Collection
54 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
55
56 class BindingMapping {
57
58
59
60     @Property
61     val Map<Type, GeneratedTypeBuilder> typeToDefinition = new HashMap();
62     
63     @Property
64     val Map<Type, SchemaNode> typeToSchemaNode = new HashMap();
65
66     def QName getSchemaNode(Class<?> cls) {
67         val ref = Types.typeForClass(cls);
68         return typeToSchemaNode.get(ref)?.QName;
69     }
70
71     def void updateBinding(SchemaContext schemaContext, ModuleContext moduleBindingContext) {
72         updateBindingFor(moduleBindingContext.childNodes, schemaContext);
73
74     }
75
76     def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
77         InstanceIdentifier<? extends DataObject> obj) {
78         val pathArguments = obj.path;
79         var Class<? extends DataObject> parent;
80         val dataDomArgs = new ArrayList<PathArgument>();
81         for (pathArgument : pathArguments) {
82             dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
83             parent = pathArgument.type;
84         }
85
86         return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
87     }
88
89     
90
91     def DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
92         if (node == null) {
93             return null;
94         }
95         val targetClass = identifier.targetType;
96         val classLoader = targetClass.classLoader;
97         val ref = Types.typeForClass(targetClass);
98         val targetType = typeToDefinition.get(ref);
99         val targetSchema = typeToSchemaNode.get(ref);
100         return node.toDataObject(classLoader, targetType.toInstance, targetSchema);
101
102     }
103
104     private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument, Class<? extends DataObject> parent) {
105         val Class rawType = argument.type;
106         val ref = Types.typeForClass(rawType);
107         val schemaType = typeToSchemaNode.get(ref);
108         val qname = schemaType.QName
109
110         val Object key = argument.key;
111         val predicates = key.toPredicates(schemaType as ListSchemaNode);
112
113         return new NodeIdentifierWithPredicates(qname, predicates);
114     }
115     
116     private def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
117         val ref = Types.typeForClass(argument.type);
118         val qname = typeToSchemaNode.get(ref).QName
119         return new NodeIdentifier(qname);
120     }
121
122     private def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
123         val keyDefinitions = node.keyDefinition;
124         val map = new HashMap<QName, Object>();
125         for (keydef : keyDefinitions) {
126             val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
127             val value = identifier.getSimpleValue(keydef, keyNode.type);
128             map.put(keydef, value.value);
129         }
130         return map;
131     }
132
133     def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
134         for (entry : map.entrySet) {
135             val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
136             typeToDefinition.put(entry.value, entry.value);
137             typeToSchemaNode.put(entry.value, schemaNode)
138         }
139     }
140
141     def CompositeNode toCompositeNode(DataContainer data) {
142         val type = data.implementedInterface;
143         val typeRef = Types.typeForClass(type);
144         val schemaNode = typeToSchemaNode.get(typeRef);
145         val generatedType = typeToDefinition.get(typeRef);
146
147         return data.toDataDom(schemaNode, generatedType);
148     }
149
150     private def dispatch CompositeNode toDataDom(DataContainer data, ContainerSchemaNode node,
151         GeneratedTypeBuilder builder) {
152         val subnodes = data.toDataDomComponents(node);
153         return new CompositeNodeTOImpl(node.QName, null, subnodes);
154     }
155
156     private def dispatch CompositeNode toDataDom(DataContainer data, NotificationDefinition node,
157         GeneratedTypeBuilder builder) {
158         val subnodes = data.toDataDomComponents(node);
159         return new CompositeNodeTOImpl(node.QName, null, subnodes);
160     }
161
162     private def dispatch CompositeNode toDataDom(DataContainer data, ListSchemaNode node,
163         GeneratedTypeBuilder builder) {
164         val subnodes = data.toDataDomComponents(node);
165         return new CompositeNodeTOImpl(node.QName, null, subnodes);
166     }
167
168     private def List<Node<?>> toDataDomComponents(DataContainer data, DataNodeContainer node) {
169         val subnodes = new ArrayList<Node<?>>();
170         for (childNode : node.childNodes) {
171             val value = childNode.dataDomFromParent(data);
172             if (value !== null) {
173                 subnodes.addAll(value);
174             }
175         }
176         return subnodes;
177     }
178
179     private def List<Node<?>> dataDomFromParent(DataSchemaNode node, DataContainer container) {
180         if (node.augmenting) {
181             return Collections.emptyList();
182         }
183         return dataDomFromParentImpl(node, container);
184     }
185
186     private def dispatch List<Node<?>> dataDomFromParentImpl(LeafSchemaNode node, DataContainer container) {
187         val value = container.getSimpleValue(node.QName, node.type);
188         if (value !== null) {
189             return Collections.<Node<?>>singletonList(value);
190         }
191         return Collections.emptyList();
192     }
193
194     private def dispatch List<Node<?>> dataDomFromParentImpl(LeafListSchemaNode node, DataContainer container) {
195         val values = container.getSimpleValues(node);
196         if (values !== null) {
197             //val it = new ArrayList<Node<?>>();
198             //for (value : values) {
199             //}
200
201         }
202         return Collections.emptyList();
203     }
204
205     private def getSimpleValues(DataContainer container, LeafListSchemaNode node) {
206         return Collections.emptyList();
207     }
208
209     private def dispatch List<Node<?>> dataDomFromParentImpl(ListSchemaNode node, DataContainer container) {
210         val qname = node.QName;
211         val values = container.<List>getValue(qname, List) as List<? extends DataContainer>;
212         if (values === null) {
213             return Collections.emptyList;
214         }
215         val it = new ArrayList<Node<?>>();
216         for (value : values) {
217             add(value.toCompositeNode());
218         }
219
220         return it;
221     }
222
223     private def dispatch List<Node<?>> dataDomFromParentImpl(ChoiceNode node, DataContainer container) {
224     }
225
226     private def dispatch List<Node<?>> serializeValueImpl(List<?> list, GeneratedTypeBuilder builder,
227         ListSchemaNode node) {
228         val it = new ArrayList<Node<?>>();
229         for (value : list) {
230
231             val serVal = value.serializeValueImpl(builder, node);
232             if (serVal !== null) {
233                 addAll(serVal);
234             }
235         }
236         return it;
237     }
238
239     public static def dispatch Node<?> getSimpleValue(Object container, QName name, ExtendedType type) {
240         getSimpleValue(container, name, type.baseType);
241     }
242
243     public static def dispatch Node<?> getSimpleValue(Object container, QName name, StringTypeDefinition type) {
244         val value = container.getValue(name, String);
245         if(value === null) return null;
246         return new SimpleNodeTOImpl(name, null, value);
247     }
248
249     public static def dispatch Node<?> getSimpleValue(Object container, QName name, TypeDefinition<?> type) {
250         val value = container.getValue(name, Object);
251         if(value === null) return null;
252         return new SimpleNodeTOImpl(name, null, value);
253     }
254
255     public static def dispatch Node<?> getSimpleValue(Object container, QName name, BooleanTypeDefinition type) {
256         val value = container.getValue(name, Boolean);
257         if(value === null) return null;
258         return new SimpleNodeTOImpl(name, null, value);
259     }
260
261     public static def dispatch Node<?> getSimpleValue(Object container, QName name, BinaryTypeDefinition type) {
262         val Object value = container.getValue(name, Object); //Constants.BYTES_CLASS);
263         if(value === null) return null;
264         return new SimpleNodeTOImpl(name, null, value);
265     }
266
267     public static def <T> T getValue(Object object, QName node, Class<T> type) {
268         val methodName = BindingGeneratorImpl.getterMethodName(node.localName, Types.typeForClass(type));
269         var clz = object.class;
270         if (object instanceof DataContainer) {
271             clz = (object as DataContainer).implementedInterface;
272         }
273         val method = clz.getMethod(methodName);
274         if (method === null) {
275             return null;
276         }
277         val value = method.invoke(object);
278         if (value === null) {
279             return null;
280         }
281         if (type.isAssignableFrom(value.class)) {
282             return value  as T;
283         }
284         return value.getEncapsulatedValue(type);
285     }
286
287     public static def <T> T getEncapsulatedValue(Object value, Class<T> type) {
288         val method = value.class.getMethod("getValue");
289         if (method !== null && type.isAssignableFrom(method.returnType)) {
290             return method.invoke(value) as T;
291         }
292         return null;
293     }
294
295     private def dispatch List<Node<?>> serializeValueImpl(DataContainer data, GeneratedTypeBuilder builder,
296         SchemaNode node) {
297         return Collections.<Node<?>>singletonList(data.toDataDom(node, builder));
298     }
299
300     private def dispatch List<Node<?>> serializeValueImpl(Object object, GeneratedTypeBuilder builder,
301         SchemaNode node) {
302     }
303
304     def DataObject toDataObject(CompositeNode node, ClassLoader loader, GeneratedType type, SchemaNode schema) {
305
306         // Nasty reflection hack (for now)
307         val builderClass = loader.loadClass(type.builderFQN);
308         val builder = builderClass.newInstance;
309         val buildMethod = builderClass.getMethod("build");
310
311         node.fillDataObject(builder, loader, type, schema);
312
313         return buildMethod.invoke(builder) as DataObject;
314     }
315
316     private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
317         ListSchemaNode schema) {
318
319         if (schema.keyDefinition !== null && !schema.keyDefinition.empty) {
320
321             val value = node.keyToBindingKey(loader, type, schema);
322             builder.setProperty("key", value);
323         }
324         node.fillBuilderFromContainer(builder,loader,type,schema);
325     }
326     
327     
328
329     private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
330         ContainerSchemaNode schema) {
331         node.fillBuilderFromContainer(builder,loader,type,schema);
332     }
333
334     
335     private def void fillBuilderFromContainer(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type, DataNodeContainer schema) {
336         val Multimap<QName,Node<?>> dataMap = ArrayListMultimap.create();
337         for(child :node.children) {
338             dataMap.put(child.nodeType,node);
339         }
340         for(entry : dataMap.asMap.entrySet) {
341             val entrySchema = schema.getDataChildByName(entry.key);
342             val entryType = type.methodDefinitions.byQName(entry.key);
343             entry.value.addValueToBuilder(builder,loader,entryType,entrySchema);
344         }
345     }
346     
347     private def Type byQName(List<MethodSignature> signatures, QName name) {
348       
349     }
350     
351     private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafSchemaNode container) {
352         
353     }
354     
355     
356     
357     private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ContainerSchemaNode container) {
358         
359     }
360     
361     
362     private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ListSchemaNode container) {
363         
364     }
365     
366     private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafListSchemaNode container) {
367         
368     }
369     
370     
371     
372     
373     private def Object keyToBindingKey(CompositeNode node, ClassLoader loader, GeneratedType type, ListSchemaNode schema) {
374         val keyClass = loader.loadClass(type.keyFQN);
375         val constructor = keyClass.constructors.get(0);
376         val keyType = type.keyTypeProperties;
377         val args = new ArrayList();
378         for (key : schema.keyDefinition) {
379             var keyProperty = keyType.get(BindingGeneratorUtil.parseToClassName(key.localName));
380             if (keyProperty == null) {
381                 keyProperty = keyType.get(BindingGeneratorUtil.parseToValidParamName(key.localName));
382             }
383             val domKeyValue = node.getFirstSimpleByName(key);
384             val keyValue = domKeyValue.deserializeSimpleValue(loader, keyProperty.returnType,
385                 schema.getDataChildByName(key));
386             args.add(keyValue);
387         }
388         return ClassLoaderUtils.construct(constructor, args);
389     }
390
391     private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
392         LeafSchemaNode node2) {
393         deserializeSimpleValueImpl(node, loader, type, node2.type);
394     }
395
396     private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
397         LeafListSchemaNode node2) {
398         deserializeSimpleValueImpl(node, loader, type, node2.type);
399     }
400
401     private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
402         ExtendedType definition) {
403         deserializeSimpleValueImpl(node, loader, type, definition.baseType);
404     }
405
406     private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
407         StringTypeDefinition definition) {
408         if (type instanceof GeneratedTransferObject) {
409             val cls = loader.getClassForType(type);
410             val const = cls.getConstructor(String);
411             val str = String.valueOf(node.value);
412             return const.newInstance(str);
413         }
414         return node.value;
415     }
416
417     private def Class<?> getClassForType(ClassLoader loader, Type type) {
418         loader.loadClass(type.fullyQualifiedName);
419     }
420
421     private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
422         TypeDefinition definition) {
423         throw new UnsupportedOperationException("TODO: auto-generated method stub")
424     }
425
426     private def Map<String, GeneratedProperty> getKeyTypeProperties(GeneratedType type) {
427         val method = FluentIterable.from(type.methodDefinitions).findFirst[name == "getKey"]
428         val key = method.returnType as GeneratedTransferObject;
429         val ret = new HashMap<String, GeneratedProperty>();
430         for (prop : key.properties) {
431             ret.put(prop.name, prop);
432         }
433         return ret;
434     }
435
436     private def void setProperty(Object object, String property, Object value) {
437         val cls = object.class;
438         val valMethod = cls.getMethod("set" + property.toFirstUpper, value.class);
439         if (valMethod != null)
440             valMethod.invoke(object, value);
441     }
442
443     private def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder'''
444
445     private def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key'''
446
447 }
448
449 @Data
450 class PropertyCapture {
451
452     @Property
453     val Type returnType;
454     @Property
455     val String name;
456
457 }