Fixed serialization of InstanceIdentifier's which contains Augmentation in path. 34/3334/8
authorTony Tkacik <ttkacik@cisco.com>
Mon, 2 Dec 2013 11:46:22 +0000 (12:46 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Mon, 2 Dec 2013 19:28:22 +0000 (20:28 +0100)
Change-Id: I0ef71ec04eaa14f95fc0f4857254eef506d78bb4
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
12 files changed:
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/YangSchemaUtils.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java

index 79a11ce278cc057c33b72feadd9272ec74b066b1..172fb05292043e49612a8bee700750c6ca68810f 100644 (file)
@@ -59,7 +59,7 @@ public class CodecMapping {
         }
     }
 
-    public static void setAugmentationCodec(Class<? extends BindingCodec<Map<QName, Object>, Object>> dataCodec,
+    public static void setAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec,
             BindingCodec<?,?> augmentableCodec) {
             Field instanceIdField;
             try {
index 0a8ea84cf60638f7290bc01ba1bfb4512d35c02c..0ac239d505b5995ce4061d158ace32aa6569a41f 100644 (file)
@@ -4,6 +4,7 @@ import java.util.Map;
 
 import org.opendaylight.yangtools.yang.binding.BindingCodec;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 
 public interface GeneratorListener {
 
@@ -13,7 +14,9 @@ public interface GeneratorListener {
     
     void onCodecCreated(Class<?> codec);
     void onValueCodecCreated(Class<?> valueClass,Class<?> valueCodec);
-    void onChoiceCodecCreated(Class<?> choiceClass,Class<? extends BindingCodec<Map<QName, Object>,Object>> choiceCodec);
     void onCaseCodecCreated(Class<?> choiceClass,Class<? extends BindingCodec<Map<QName, Object>,Object>> choiceCodec);
-    public abstract void onDataContainerCodecCreated(Class<?> dataClass, Class<?  extends BindingCodec<Map<QName, Object>,Object>> dataCodec);
+    void onDataContainerCodecCreated(Class<?> dataClass, Class<?  extends BindingCodec<?,?>> dataCodec);
+
+    void onChoiceCodecCreated(Class<?> choiceClass,
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec, ChoiceNode schema);
 }
index 270660980643cfa6e58a1bcc5fc7aeff856fc584..150d0f199f83f5615a9a5a8b7bda07347e6be309 100644 (file)
@@ -22,6 +22,10 @@ import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
 import org.opendaylight.yangtools.yang.data.api.Node
 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.binding.Augmentable
+import com.google.common.collect.ImmutableList
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import java.util.concurrent.ConcurrentHashMap
 
 class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     
@@ -29,7 +33,7 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     val CodecRegistry codecRegistry;
     
     val Map<Class<?>,QName> classToQName = new WeakHashMap;
-    
+    val Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = new WeakHashMap;
     
     public new(CodecRegistry registry) {
         codecRegistry = registry;
@@ -44,8 +48,15 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
         for(biArg : biArgs) {
             scannedPath.add(biArg.nodeType);
             val baArg = deserializePathArgument(biArg,scannedPath)
-            baArgs.add(baArg)
             baType = baArg?.type
+            val injectAugment = classToPreviousAugment.get(baType);
+            if(injectAugment != null) {
+                val augment = injectAugment.get(scannedPath) as Class<? extends DataObject>;
+                if(augment != null) {
+                    baArgs.add(new Item(augment));
+                }
+            }
+            baArgs.add(baArg)
         }
         val ret = new InstanceIdentifier(baArgs,baType as Class<? extends DataObject>);
         return ret;
@@ -74,18 +85,41 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
     }
     
     override serialize(InstanceIdentifier input) {
+        var Class<?> previousAugmentation = null
         val pathArgs = input.path as List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument>
         var QName previousQName = null;
         val components = new ArrayList<PathArgument>(pathArgs.size);
+        val qnamePath = new ArrayList<QName>(pathArgs.size);
         for(baArg : pathArgs) { 
-            codecRegistry.bindingClassEncountered(baArg.type);
-            val biArg = serializePathArgument(baArg,previousQName);
-            previousQName = biArg.nodeType;
-            components.add(biArg);
+            
+            if(!Augmentation.isAssignableFrom(baArg.type)) {
+                
+                val biArg = serializePathArgument(baArg,previousQName);
+                previousQName = biArg.nodeType;
+                components.add(biArg);
+                qnamePath.add(biArg.nodeType);
+                val immutableList = ImmutableList.copyOf(qnamePath);
+                codecRegistry.putPathToClass(immutableList,baArg.type);
+                if(previousAugmentation !== null) {
+                    updateAugmentationInjection(baArg.type,immutableList,previousAugmentation)
+                }
+                
+                previousAugmentation = null;
+            } else {
+                previousQName = resolveQname(baArg.type);
+                previousAugmentation = baArg.type;
+            }
         }
         return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(components);
     }
     
+    def updateAugmentationInjection(Class<? extends DataObject> class1, ImmutableList<QName> list, Class<?> augmentation) {
+        if(classToPreviousAugment.get(class1) == null) {
+            classToPreviousAugment.put(class1,new ConcurrentHashMap());
+        }
+        classToPreviousAugment.get(class1).put(list,augmentation);
+    }
+    
     private def dispatch PathArgument serializePathArgument(Item argument, QName previousQname) {
         val type = argument.type;
         val qname = resolveQname(type);
index 961cb2eb598bf7f8aaa0c45bbb9dbe2d5d303839..de6836489e6a6b970fb96a409e832876d02e82a7 100644 (file)
@@ -26,6 +26,7 @@ import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
 import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils;
 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -40,6 +41,8 @@ import org.opendaylight.yangtools.yang.binding.Identifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -48,6 +51,7 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,6 +65,8 @@ import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTy
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
+import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering;
+
 public class LazyGeneratedCodecRegistry implements //
         CodecRegistry, //
         SchemaServiceListener, //
@@ -90,6 +96,7 @@ public class LazyGeneratedCodecRegistry implements //
     private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
 
     Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+    Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
 
     private SchemaContext currentSchema;
 
@@ -116,15 +123,27 @@ public class LazyGeneratedCodecRegistry implements //
     public Class<?> getClassForPath(List<QName> names) {
         DataSchemaNode node = getSchemaNode(names);
         SchemaPath path = node.getPath();
-        GeneratedTypeBuilder type = pathToType.get(path);
-        ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+        Type type = pathToType.get(path);
+        if (type != null) {
+            type = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+        } else {
+            type = pathToInstantiatedType.get(names);
+        }
         @SuppressWarnings("rawtypes")
-        WeakReference<Class> weakRef = typeToClass.get(typeref);
-        if(weakRef == null) {
-            LOG.error("Could not find loaded class for path: {} and type: {}",path,typeref.getFullyQualifiedName());
+        WeakReference<Class> weakRef = typeToClass.get(type);
+        if (weakRef == null) {
+            LOG.error("Could not find loaded class for path: {} and type: {}", path, type.getFullyQualifiedName());
         }
         return weakRef.get();
     }
+    
+    @Override
+    public void putPathToClass(List<QName> names,Class<?> cls) {
+        Type reference = Types.typeForClass(cls);
+        pathToInstantiatedType.put(names, reference );
+        bindingClassEncountered(cls);
+    }
+
 
     @Override
     public IdentifierCodec<?> getKeyCodecForPath(List<QName> names) {
@@ -150,27 +169,29 @@ public class LazyGeneratedCodecRegistry implements //
     @Override
     @SuppressWarnings("rawtypes")
     public void bindingClassEncountered(Class cls) {
-        
+
         ConcreteType typeRef = Types.typeForClass(cls);
-        if(typeToClass.containsKey(typeRef)) {
+        if (typeToClass.containsKey(typeRef)) {
             return;
         }
-        LOG.info("Binding Class {} encountered.",cls);
+        LOG.info("Binding Class {} encountered.", cls);
         WeakReference<Class> weakRef = new WeakReference<>(cls);
         typeToClass.put(typeRef, weakRef);
-        if(DataObject.class.isAssignableFrom(cls)) {
-            @SuppressWarnings({"unchecked","unused"})
+        if (Augmentation.class.isAssignableFrom(cls)) {
+
+        } else if (DataObject.class.isAssignableFrom(cls)) {
+            @SuppressWarnings({ "unchecked", "unused" })
             Object cdc = getCodecForDataObject((Class<? extends DataObject>) cls);
         }
     }
-    
+
     @Override
     public void onClassProcessed(Class<?> cls) {
         ConcreteType typeRef = Types.typeForClass(cls);
-        if(typeToClass.containsKey(typeRef)) {
+        if (typeToClass.containsKey(typeRef)) {
             return;
         }
-        LOG.info("Binding Class {} encountered.",cls);
+        LOG.info("Binding Class {} encountered.", cls);
         WeakReference<Class> weakRef = new WeakReference<>((Class) cls);
         typeToClass.put(typeRef, weakRef);
     }
@@ -294,7 +315,6 @@ public class LazyGeneratedCodecRegistry implements //
 
     public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
         pathToType.putAll(context.getChildNodes());
-
         captureCases(context.getCases(), schemaContext);
     }
 
@@ -309,6 +329,7 @@ public class LazyGeneratedCodecRegistry implements //
                 continue;
             }
 
+            pathToType.put(caseNode.getKey(), caseNode.getValue());
             @SuppressWarnings("rawtypes")
             ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
             typeToCaseNodes.putIfAbsent(typeref, value);
@@ -323,7 +344,7 @@ public class LazyGeneratedCodecRegistry implements //
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public void onChoiceCodecCreated(Class<?> choiceClass,
-            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
+            Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec, ChoiceNode schema) {
         ChoiceCodec<?> oldCodec = choiceCodecs.get(choiceClass);
         checkState(oldCodec == null);
         BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
@@ -331,6 +352,22 @@ public class LazyGeneratedCodecRegistry implements //
         choiceCodecs.put(choiceClass, newCodec);
         CodecMapping.setClassToCaseMap(choiceCodec, (Map<Class<?>, BindingCodec<?, ?>>) classToCaseRawCodec);
         CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
+        
+        tryToCreateCasesCodecs(schema);
+
+    }
+
+    private void tryToCreateCasesCodecs(ChoiceNode schema) {
+        for(ChoiceCaseNode caseNode : schema.getCases()) {
+            SchemaPath path = caseNode.getPath();
+            GeneratedTypeBuilder type;
+            if(path != null && (type = pathToType.get(path)) != null) {
+                Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
+                if(caseClass != null) {
+                    getCaseCodecFor(caseClass);
+                }
+            }
+        }
 
     }
 
@@ -345,7 +382,7 @@ public class LazyGeneratedCodecRegistry implements //
 
     @Override
     public void onDataContainerCodecCreated(Class<?> dataClass,
-            Class<? extends BindingCodec<Map<QName, Object>, Object>> dataCodec) {
+            Class<? extends BindingCodec<?,?>> dataCodec) {
         if (Augmentable.class.isAssignableFrom(dataClass)) {
             AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
             CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
@@ -478,7 +515,7 @@ public class LazyGeneratedCodecRegistry implements //
 
         @Override
         public boolean isAcceptable(Node<?> input) {
-            if (!(input instanceof CompositeNode)) {
+            if (input instanceof CompositeNode) {
                 if (augmenting) {
                     return checkAugmenting((CompositeNode) input);
                 } else {
@@ -492,7 +529,8 @@ public class LazyGeneratedCodecRegistry implements //
             QName parent = input.getNodeType();
             for (Node<?> childNode : input.getChildren()) {
                 QName child = childNode.getNodeType();
-                if (!Objects.equals(parent.getNamespace(), child.getNamespace()) || Objects.equals(parent.getRevision(), child.getRevision())) {
+                if (!Objects.equals(parent.getNamespace(), child.getNamespace())
+                        || !Objects.equals(parent.getRevision(), child.getRevision())) {
                     continue;
                 }
                 if (validNames.contains(child.getLocalName())) {
@@ -562,7 +600,7 @@ public class LazyGeneratedCodecRegistry implements //
         public BindingCodec get(Object key) {
             if (key instanceof Class) {
                 Class cls = (Class) key;
-                //bindingClassEncountered(cls);
+                // bindingClassEncountered(cls);
                 ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls);
                 return caseCodec.getDelegate();
             }
@@ -592,8 +630,7 @@ public class LazyGeneratedCodecRegistry implements //
             }
             return null;
         }
-        
-        
+
     }
 
     /**
@@ -641,7 +678,7 @@ public class LazyGeneratedCodecRegistry implements //
         }
 
         @Override
-        public BindingCodec<Map<QName, Object>, Object> put(T key, BindingCodec<?,?> value) {
+        public BindingCodec<Map<QName, Object>, Object> put(T key, BindingCodec<?, ?> value) {
             throw notModifiable();
         }
 
@@ -705,9 +742,9 @@ public class LazyGeneratedCodecRegistry implements //
                 augmentationField.setAccessible(true);
                 Map<Class, Augmentation> augMap = (Map<Class, Augmentation>) augmentationField.get(input);
                 return augMap;
-            } catch (IllegalArgumentException | IllegalAccessException |NoSuchFieldException | SecurityException e) {
-                LOG.debug("Could not read augmentations for {}",input,e);
-            } 
+            } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+                LOG.debug("Could not read augmentations for {}", input, e);
+            }
             return Collections.emptyMap();
         }
 
@@ -732,9 +769,9 @@ public class LazyGeneratedCodecRegistry implements //
                 rawAugmentationCodecs.put(key, ret);
                 return ret;
             } catch (InstantiationException e) {
-                LOG.error("Can not instantiate raw augmentation codec {}",key.getSimpleName(),e);
+                LOG.error("Can not instantiate raw augmentation codec {}", key.getSimpleName(), e);
             } catch (IllegalAccessException e) {
-                LOG.debug("BUG: Constructor for {} is not accessible.",key.getSimpleName(),e);
+                LOG.debug("BUG: Constructor for {} is not accessible.", key.getSimpleName(), e);
             }
             return null;
         }
index 0da7aec480e2c4f3d470cc9b02ad4c386f8f101f..7eb473ce3401a6774ed31f9690db658f24e4a576 100644 (file)
@@ -35,6 +35,8 @@ 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
 
 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
 
@@ -83,8 +85,17 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
             updateBindingFor(context.cases, schemaContext);
 
             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) {
@@ -114,7 +125,14 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         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;
+        }
+        
         val ref = Types.typeForClass(class1);
         getSchemaWithRetry(ref);
     }
@@ -161,9 +179,10 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
 
             //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
             if (schemaNode != null) {
-                typeToSchemaNode.put(entry.value, schemaNode);
-                typeToDefinition.put(entry.value, entry.value);
-                updatePromisedSchemas(entry.value, schemaNode);
+                val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
+                typeToSchemaNode.put(typeRef, schemaNode);
+                typeToDefinition.put(typeRef, entry.value);
+                updatePromisedSchemas(typeRef, schemaNode);
             }
         }
     }
@@ -213,6 +232,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         if (typeDef !== null) {
             return typeDef;
         }
+        LOG.info("Thread blocked waiting for schema for: {}",type.fullyQualifiedName)
         return type.getSchemaInFuture.get();
     }
 
index ab2e96f05c09b0e79502547e9502ffc697dd8b2b..a732f152b25675612a21a3a6aad503c5971dbdaa 100644 (file)
@@ -46,6 +46,9 @@ import java.util.Iterator
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
 import java.util.concurrent.ConcurrentHashMap
 import static extension org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils.*;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
+import org.opendaylight.yangtools.yang.model.util.ExtendedType
+import org.opendaylight.yangtools.yang.model.util.EnumerationType
 
 class TransformerGenerator {
 
@@ -221,6 +224,19 @@ class TransformerGenerator {
         ]
     }
 
+    private def Class<?> getValueSerializer(Enumeration type) {
+        val cls = loadClassWithTCCL(type.resolvedName);
+        val transformer = cls.generatedClass;
+        if (transformer !== null) {
+            return transformer;
+        }
+
+        return withClassLoaderAndLock(cls.classLoader, lock) [ |
+            val valueTransformer = generateValueTransformer(cls, type);
+            return valueTransformer;
+        ]
+    }
+
     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
         try {
 
@@ -342,16 +358,18 @@ class TransformerGenerator {
                 method(Object, "deserialize", Object) [
                     body = '''
                         {
-                            
-                            return fromDomStatic(QNAME,$1);
+                            //System.out.println("«type.name»#deserialize: " +$1);
+                            java.util.Map.Entry _input = (java.util.Map.Entry) $1;
+                            return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue());
                         }
                     '''
                 ]
             ]
 
-            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)  as Class<? extends BindingCodec<Object, Object>>
+            listener?.onDataContainerCodecCreated(inputType,ret);
             log.info("DOM Codec for {} was generated {}", inputType, ret)
-            return ret as Class<? extends BindingCodec<Object, Object>>;
+            return ret;
         } catch (Exception e) {
             processException(inputType, e);
             return null;
@@ -548,7 +566,7 @@ class TransformerGenerator {
 
             val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
             val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
-            listener?.onChoiceCodecCreated(inputType, ret);
+            listener?.onChoiceCodecCreated(inputType, ret, node);
             log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret;
         } catch (Exception e) {
@@ -759,6 +777,10 @@ class TransformerGenerator {
         («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»)
     '''
 
+    private def dispatch String deserializeValue(Enumeration type, String domParameter) '''
+        («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»)
+    '''
+
     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
         Class<?> inputType, GeneratedTransferObject typeSpec) {
         try {
@@ -888,6 +910,9 @@ class TransformerGenerator {
 
     private def dispatch Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec) {
         try {
+            val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name);
+            val schema = typeToSchemaNode.get(typeRef) as ExtendedType;
+            val enumSchema = schema.baseType as EnumerationType;
 
             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
             val ctCls = createClass(typeSpec.codecClassName) [
@@ -895,12 +920,18 @@ class TransformerGenerator {
                 //implementsType(BINDING_CODEC)
                 method(Object, "toDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
-                    body = '''
-                        if($1 == null) {
+                    body = '''{
+                            if($1 == null) {
+                                return null;
+                            }
+                            «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
+                            «FOR en : enumSchema.values»
+                            if(«typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)».equals(_value)) {
+                                return "«en.name»";
+                            }
+                            «ENDFOR»
                             return null;
                         }
-                        «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
-                        return _value.getValue();
                     '''
                 ]
                 method(Object, "serialize", Object) [
@@ -911,12 +942,18 @@ class TransformerGenerator {
                 method(Object, "fromDomValue", Object) [
                     modifiers = PUBLIC + FINAL + STATIC
                     body = '''
-                        if($1 == null) {
+                        {
+                            if($1 == null) {
+                                return null;
+                            }
+                            String _value = (String) $1;
+                            «FOR en : enumSchema.values»
+                                if("«en.name»".equals(_value)) {
+                                    return «typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)»;
+                                }
+                            «ENDFOR»
                             return null;
                         }
-                        _simpleValue = null;
-                        «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(null);
-                        return _value;
                     '''
                 ]
                 method(Object, "deserialize", Object) [
@@ -1126,6 +1163,8 @@ class TransformerGenerator {
     private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.
         resolvedName».toDomValue(«parameter»)'''
 
+    private def dispatch serializeValue(Enumeration type, String parameter) '''«type.valueSerializer.resolvedName».toDomValue(«parameter»)'''
+
     private def dispatch serializeValue(Type signature, String property) {
         if (INSTANCE_IDENTIFIER == signature) {
             return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
index 02c59b2779ccd511975bd4fa8109b1e2700e6d0d..5db522f56c34b6c6816b067d96441034a01dfed1 100644 (file)
@@ -1,8 +1,9 @@
 package org.opendaylight.controller.sal.binding.impl;\r
 \r
+import java.util.Set;
 import java.util.concurrent.Future;\r
 import java.util.concurrent.atomic.AtomicLong;\r
-\r
+
 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;\r
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;\r
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;\r
@@ -99,5 +100,21 @@ public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? exte
     @Override\r
     public void close() throws Exception {\r
         \r
+    }
+    
+    
+    @Override
+    protected boolean isAffectedBy(InstanceIdentifier<? extends DataObject> key,
+            Set<InstanceIdentifier<? extends DataObject>> paths) {
+        if (paths.contains(key)) {
+            return true;
+        }
+        for (InstanceIdentifier<?> path : paths) {
+            if (key.containsWildcarded(path)) {
+                return true;
+            }
+        }
+
+        return false;
     }\r
 }
\ No newline at end of file
index 864c048a9133a71350d339ff3b62daae109bc44f..5f3189f7d2a196593ec2c903c1a2eb717c488ac5 100644 (file)
@@ -116,7 +116,7 @@ public class BindingIndependentDataServiceConnector implements //
                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
                 target.putConfigurationData(baKey, baData);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry.getKey(), e);
+                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
             }
         }
         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
@@ -127,7 +127,7 @@ public class BindingIndependentDataServiceConnector implements //
                 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
                 target.putOperationalData(baKey, baData);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry.getKey(), e);
+                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
             }
         }
         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
@@ -136,7 +136,7 @@ public class BindingIndependentDataServiceConnector implements //
                 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
                 target.removeConfigurationData(baEntry);
             } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
+                LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry, e);
             }
         }
         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
@@ -312,7 +312,6 @@ public class BindingIndependentDataServiceConnector implements //
 
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
                     .getPath());
-            // FIXME: do registration based on only active commit handlers.
 
         }
 
index cb3206a3b30f8709fda36137ebd218edb8d4e06e..596329e07b1cdb23b2642d3f97e943aebcbf579a 100644 (file)
@@ -59,4 +59,13 @@ public final class ClassLoaderUtils {
 
         return Thread.currentThread().getContextClassLoader().loadClass(name);
     }
+
+    public static Class<?> tryToLoadClassWithTCCL(String fullyQualifiedName) {
+        try {
+            return loadClassWithTCCL(fullyQualifiedName);
+        } catch (ClassNotFoundException e) {
+            
+        }
+        return null;
+    }
 }
\ No newline at end of file
index b7a21cb022aa59011f6a66314d772e5e867fd911..1426089360ef2bd3c8e0530341e0b66cff8ee81f 100644 (file)
@@ -4,11 +4,16 @@ import java.util.List;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 
 import com.google.common.base.Preconditions;
 
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
 public class YangSchemaUtils {
 
     public static final String AUGMENT_IDENTIFIER = "augment-identifier";
@@ -41,4 +46,25 @@ public class YangSchemaUtils {
         }
         return null;
     }
+
+
+    public static TypeDefinition<?> findTypeDefinition(SchemaContext context, SchemaPath path) {
+        List<QName> arguments = path.getPath();
+        QName first = arguments.get(0);
+        QName typeQName = arguments.get(arguments.size() -1);
+        DataNodeContainer previous = context.findModuleByNamespaceAndRevision(first.getNamespace(), first.getRevision());
+        if(previous == null) {
+            return null;
+        }
+        Preconditions.checkArgument(arguments.size() == 1);
+        for (QName qName : arguments) {
+            //previous.getDataChildByName(qName);
+        }
+        for(TypeDefinition<?> typedef : previous.getTypeDefinitions()) {
+            if(typedef.getQName().equals(typeQName)) {
+                return typedef;
+            }
+        }
+        return null;
+    }
 }
index 91163d80f2ff4f4db1dbfec370aa5a2cd801a737..d3ef2f3d6eaee93f728b724b0cb9fdd5b95a7b0a 100644 (file)
@@ -1,8 +1,9 @@
 package org.opendaylight.controller.sal.binding.test.bugfix;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
-
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
@@ -11,6 +12,10 @@ import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
@@ -19,15 +24,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
-
-
 import static org.junit.Assert.*;
 
 public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener {
@@ -44,14 +50,34 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
             .toInstance();
 
 
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(NODES_INSTANCE_ID_BA) //
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
+            .builder(NODES_INSTANCE_ID_BA) //
             .child(Node.class, NODE_KEY).toInstance();
+    
+    
+    private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
+            .builder(NODES_INSTANCE_ID_BA) //
+            .child(Node.class, NODE_KEY) //
+            .augmentation(FlowCapableNode.class) //
+            .child(SupportedActions.class)
+            .toInstance();
+    
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
             .node(Nodes.QNAME) //
             .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
             .toInstance();
+    private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+
+    
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+                    .node(Nodes.QNAME) //
+                    .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+                    .node(SUPPORTED_ACTIONS_QNAME) //
+                    .toInstance();
+    
     private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
 
     
@@ -94,11 +120,31 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         Nodes nodes = checkForNodes();
         verifyNodes(nodes,original);
         
-        
-        
         testAddingNodeConnector();
         testNodeRemove();
+
+    }
+    
+    @Test
+    public void testAugmentNestedSerialization() throws Exception {
+        DataModificationTransaction transaction = baDataService.beginTransaction();
+        
+        SupportedActionsBuilder actions = new SupportedActionsBuilder();
+        ActionTypeBuilder action = new ActionTypeBuilder();
+        action.setAction("foo-action");
+        action.setSupportState(SupportType.Native);
+        List<ActionType> actionTypes = Collections.singletonList(action.build());
+        actions.setActionType(actionTypes );
         
+        transaction.putOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA, actions.build());
+        RpcResult<TransactionStatus> putResult = transaction.commit().get();
+        assertNotNull(putResult);
+        assertEquals(TransactionStatus.COMMITED, putResult.getResult());
+        SupportedActions readedTable = (SupportedActions) baDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA);
+        assertNotNull(readedTable);
+        
+        CompositeNode biSupportedActions = biDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BI);
+        assertNotNull(biSupportedActions);
         
     }
 
@@ -121,10 +167,6 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         assertFalse(node.getNodeConnector().isEmpty());
         NodeConnector readedNc = node.getNodeConnector().get(0);
         assertNotNull(readedNc);
-        
-        
-        
-        
     }
 
     private void testNodeRemove() throws Exception {