1 package org.opendaylight.controller.sal.binding.impl.connect.dom
3 import org.opendaylight.yangtools.yang.common.QName
4 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext
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
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
56 class BindingMapping {
61 val Map<Type, GeneratedTypeBuilder> typeToDefinition = new HashMap();
64 val Map<Type, SchemaNode> typeToSchemaNode = new HashMap();
66 def QName getSchemaNode(Class<?> cls) {
67 val ref = Types.typeForClass(cls);
68 return typeToSchemaNode.get(ref)?.QName;
71 def void updateBinding(SchemaContext schemaContext, ModuleContext moduleBindingContext) {
72 updateBindingFor(moduleBindingContext.childNodes, schemaContext);
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;
86 return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
91 def DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
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);
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
110 val Object key = argument.key;
111 val predicates = key.toPredicates(schemaType as ListSchemaNode);
113 return new NodeIdentifierWithPredicates(qname, predicates);
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);
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);
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)
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);
147 return data.toDataDom(schemaNode, generatedType);
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);
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);
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);
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);
179 private def List<Node<?>> dataDomFromParent(DataSchemaNode node, DataContainer container) {
180 if (node.augmenting) {
181 return Collections.emptyList();
183 return dataDomFromParentImpl(node, container);
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);
191 return Collections.emptyList();
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) {
202 return Collections.emptyList();
205 private def getSimpleValues(DataContainer container, LeafListSchemaNode node) {
206 return Collections.emptyList();
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;
215 val it = new ArrayList<Node<?>>();
216 for (value : values) {
217 add(value.toCompositeNode());
223 private def dispatch List<Node<?>> dataDomFromParentImpl(ChoiceNode node, DataContainer container) {
226 private def dispatch List<Node<?>> serializeValueImpl(List<?> list, GeneratedTypeBuilder builder,
227 ListSchemaNode node) {
228 val it = new ArrayList<Node<?>>();
231 val serVal = value.serializeValueImpl(builder, node);
232 if (serVal !== null) {
239 public static def dispatch Node<?> getSimpleValue(Object container, QName name, ExtendedType type) {
240 getSimpleValue(container, name, type.baseType);
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);
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);
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);
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);
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;
273 val method = clz.getMethod(methodName);
274 if (method === null) {
277 val value = method.invoke(object);
278 if (value === null) {
281 if (type.isAssignableFrom(value.class)) {
284 return value.getEncapsulatedValue(type);
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;
295 private def dispatch List<Node<?>> serializeValueImpl(DataContainer data, GeneratedTypeBuilder builder,
297 return Collections.<Node<?>>singletonList(data.toDataDom(node, builder));
300 private def dispatch List<Node<?>> serializeValueImpl(Object object, GeneratedTypeBuilder builder,
304 def DataObject toDataObject(CompositeNode node, ClassLoader loader, GeneratedType type, SchemaNode schema) {
306 // Nasty reflection hack (for now)
307 val builderClass = loader.loadClass(type.builderFQN);
308 val builder = builderClass.newInstance;
309 val buildMethod = builderClass.getMethod("build");
311 node.fillDataObject(builder, loader, type, schema);
313 return buildMethod.invoke(builder) as DataObject;
316 private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
317 ListSchemaNode schema) {
319 if (schema.keyDefinition !== null && !schema.keyDefinition.empty) {
321 val value = node.keyToBindingKey(loader, type, schema);
322 builder.setProperty("key", value);
324 node.fillBuilderFromContainer(builder,loader,type,schema);
329 private def dispatch void fillDataObject(CompositeNode node, Object builder, ClassLoader loader, GeneratedType type,
330 ContainerSchemaNode schema) {
331 node.fillBuilderFromContainer(builder,loader,type,schema);
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);
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);
347 private def Type byQName(List<MethodSignature> signatures, QName name) {
351 private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafSchemaNode container) {
357 private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ContainerSchemaNode container) {
362 private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, ListSchemaNode container) {
366 private def dispatch addValueToBuilder(Collection<Node<? extends Object>> nodes, Object object, ClassLoader loader, Object object2, LeafListSchemaNode container) {
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));
383 val domKeyValue = node.getFirstSimpleByName(key);
384 val keyValue = domKeyValue.deserializeSimpleValue(loader, keyProperty.returnType,
385 schema.getDataChildByName(key));
388 return ClassLoaderUtils.construct(constructor, args);
391 private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
392 LeafSchemaNode node2) {
393 deserializeSimpleValueImpl(node, loader, type, node2.type);
396 private def dispatch Object deserializeSimpleValue(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
397 LeafListSchemaNode node2) {
398 deserializeSimpleValueImpl(node, loader, type, node2.type);
401 private def dispatch Object deserializeSimpleValueImpl(SimpleNode<? extends Object> node, ClassLoader loader, Type type,
402 ExtendedType definition) {
403 deserializeSimpleValueImpl(node, loader, type, definition.baseType);
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);
417 private def Class<?> getClassForType(ClassLoader loader, Type type) {
418 loader.loadClass(type.fullyQualifiedName);
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")
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);
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);
443 private def String getBuilderFQN(Type type) '''«type.fullyQualifiedName»Builder'''
445 private def String getKeyFQN(Type type) '''«type.fullyQualifiedName»Key'''
450 class PropertyCapture {