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