Merge "Improve iteration over subnets map by using entrySet instead of keyset. It...
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / dom / serializer / impl / RuntimeGeneratedMappingServiceImpl.xtend
index ec69fd3b68c8ee84c39edde4e58207adb771b5bd..1b3acf7674eda63e4430ec8d61b7ef186a2b6c80 100644 (file)
@@ -35,6 +35,19 @@ import java.util.Hashtable
 import org.osgi.framework.ServiceRegistration
 import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationException
 import java.util.concurrent.Callable
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.binding.RpcService
+import java.util.Set
+import org.opendaylight.yangtools.yang.common.QName
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 
 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
 
@@ -57,6 +70,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
     @Property
     val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+    
+    @Property
+    val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap(); 
 
     val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
 
@@ -76,15 +92,31 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         for (entry : newBinding.moduleContexts.entrySet) {
 
             registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
-
-            //val module = entry.key;
+            binding.pathToType.putAll(entry.value.childNodes)
+            val module = entry.key;
             val context = entry.value;
             updateBindingFor(context.childNodes, schemaContext);
             updateBindingFor(context.cases, schemaContext);
+            val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+            
+            if(!module.rpcs.empty) {
+            val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
+            val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
+                serviceTypeToRpc.put(serviceClass,rpcs);
+            }
 
             val typedefs = context.typedefs;
-            for (typedef : typedefs.values) {
-                binding.typeDefinitions.put(typedef, typedef as GeneratedType);
+            for (typedef : typedefs.entrySet) {
+                val typeRef = new ReferencedTypeImpl(typedef.value.packageName,typedef.value.name)
+                binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType);
+                val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext,typedef.key);
+                if(schemaNode != null) {
+                    
+                    binding.typeToSchemaNode.put(typeRef,schemaNode);
+                } else {
+                    LOG.error("Type definition for {} is not available",typedef.value);
+                }
+                
             }
             val augmentations = context.augmentations;
             for (augmentation : augmentations) {
@@ -101,9 +133,21 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
     override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
         Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+        
+        try {
         val key = toDataDom(entry.key)
-        val data = toCompositeNodeImpl(entry.value);
+        var CompositeNode data;
+        if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+            data = toCompositeNodeImpl(key,entry.value);
+        } else {
+          data = toCompositeNodeImpl(entry.value);
+        }
         return new SimpleEntry(key, data);
+        
+        } catch (Exception e) {
+            LOG.error("Error during serialization for {}.", entry.key,e);
+            throw e;
+        }
     }
 
     private def CompositeNode toCompositeNodeImpl(DataObject object) {
@@ -113,8 +157,37 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         val ret = codec.serialize(new ValueWithQName(null, object));
         return ret as CompositeNode;
     }
+    
+    
+    private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+       
+        //val cls = object.implementedInterface;
+        //waitForSchema(cls);
+        val last = identifier.path.last;
+        val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+        val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+        if(last instanceof NodeIdentifierWithPredicates) {
+            val predicates = last as NodeIdentifierWithPredicates;
+            val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+            for(predicate : predicates.keyValues.entrySet) {
+                newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+            }
+            newNodes.addAll(ret.children);
+            return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+        }
+        return ret as CompositeNode;
+    }
 
-    private def waitForSchema(Class<? extends DataContainer> class1) {
+    private def void waitForSchema(Class<? extends DataContainer> class1) {
+        if(Augmentation.isAssignableFrom(class1)) {
+            /*  FIXME: We should wait also for augmentations. Currently YANGTools does not provide correct
+             *  mapping between java Augmentation classes and augmentations.
+             */
+            return;
+        }
+        if(registry.isCodecAvailable(class1)) {
+            return;
+        }
         val ref = Types.typeForClass(class1);
         getSchemaWithRetry(ref);
     }
@@ -128,15 +201,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
     }
 
     override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
-        return tryDeserialization[ |
-            if (node == null) {
-                return null;
-            }
-            val targetType = path.targetType
-            val transformer = registry.getCodecForDataObject(targetType);
-            val ret = transformer.deserialize(node)?.value as DataObject;
-            return ret;
-        ]
+         dataObjectFromDataDom(path.targetType,node) as DataObject;
     }
 
     override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
@@ -149,21 +214,25 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         try {
             deserializationBlock.call()
         } catch (Exception e) {
+
             // FIXME: Make this block providing more information.
             throw new DeserializationException(e);
         }
     }
 
     private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
+        
         for (entry : map.entrySet) {
             val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
 
             //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
+            val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
+            typeToDefinition.put(typeRef, entry.value);
             if (schemaNode != null) {
-                typeToSchemaNode.put(entry.value, schemaNode);
-                typeToDefinition.put(entry.value, entry.value);
-                updatePromisedSchemas(entry.value, schemaNode);
+                typeToSchemaNode.put(typeRef, schemaNode);
+                updatePromisedSchemas(typeRef, schemaNode);
             }
+            
         }
     }
 
@@ -181,30 +250,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
             listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
         }
     }
-
-    private def getTypeDefinition(Type type) {
-        val typeDef = typeToDefinition.get(type);
-        if (typeDef !== null) {
-            return typeDef;
-        }
-        return type.getTypeDefInFuture.get();
-    }
-
-    private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
-        val future = SettableFuture.<GeneratedTypeBuilder>create()
-        promisedTypeDefinitions.put(type, future);
-        return future;
-    }
-
-    private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
-        val futures = promisedTypeDefinitions.get(builder);
-        if (futures === null || futures.empty) {
-            return;
-        }
-        for (future : futures) {
-            future.set(builder);
-        }
-        promisedTypeDefinitions.removeAll(builder);
+    
+    override getRpcQNamesFor(Class<? extends RpcService> service) {
+        return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
     }
 
     private def getSchemaWithRetry(Type type) {
@@ -212,6 +260,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         if (typeDef !== null) {
             return typeDef;
         }
+        LOG.info("Thread blocked waiting for schema for: {}",type.fullyQualifiedName)
         return type.getSchemaInFuture.get();
     }
 
@@ -236,5 +285,16 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
     override close() throws Exception {
         listenerRegistration?.unregister();
     }
+    
+    override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
+        return tryDeserialization[ |
+            if (domData == null) {
+                return null;
+            }
+            val transformer = registry.getCodecForDataObject(container);
+            val ret = transformer.deserialize(domData)?.value as DataObject;
+            return ret;
+        ]
+    }
 
 }