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