Fix for Bug 144 53/2753/1
authorTony Tkacik <ttkacik@cisco.com>
Thu, 14 Nov 2013 19:07:29 +0000 (20:07 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Thu, 14 Nov 2013 19:07:29 +0000 (20:07 +0100)
  - Fixed bug in generated code which tried to access non-existing field
  - Added common root for tests dealing with models and their storage.
  - Added regresion unit test to test situation from original bug report.

Change-Id: If71d5dab8f188c0189aa343859321d238188a76e
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/CodeGenerationException.java [new file with mode: 0644]
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/connect/dom/BindingMapping.xtend
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/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java

index 9e4d3a580c79888da155bd9a5808971862ffed84..c356ff6b0e15258127524119d28f057d9a993755 100644 (file)
             <version>1.0-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-flow-management</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-data-impl</artifactId>
             <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.reflections</groupId>
+            <artifactId>reflections</artifactId>
+            <version>0.9.9-RC1</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/CodeGenerationException.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/CodeGenerationException.java
new file mode 100644 (file)
index 0000000..1923040
--- /dev/null
@@ -0,0 +1,25 @@
+package org.opendaylight.controller.sal.binding.codegen;
+
+public class CodeGenerationException extends RuntimeException{
+
+    public CodeGenerationException() {
+        super();
+    }
+
+    public CodeGenerationException(String message, Throwable cause, boolean enableSuppression,
+            boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+    public CodeGenerationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CodeGenerationException(String message) {
+        super(message);
+    }
+
+    public CodeGenerationException(Throwable cause) {
+        super(cause);
+    }
+}
index 2d67f11eb2b1b65046890fdfa816283a2c0dc483..2136572aa3240117ced443e180acc8b6c26d68be 100644 (file)
@@ -34,6 +34,10 @@ import org.opendaylight.yangtools.yang.binding.BindingDeserializer
 import org.opendaylight.yangtools.yang.binding.BindingSerializer
 import org.opendaylight.yangtools.yang.binding.BindingCodec
 import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.binding.codegen.CodeGenerationException
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode
+import java.security.ProtectionDomain
+import java.io.File
 
 class TransformerGenerator {
 
@@ -53,6 +57,10 @@ class TransformerGenerator {
 
     CtClass ctQName
 
+    @Property
+    var File classFileCapturePath;
+
+
     @Property
     var Map<Type, Type> typeDefinitions;
 
@@ -88,7 +96,7 @@ class TransformerGenerator {
         ]
     }
 
-    def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
+    private def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
         return withClassLoader(inputType.classLoader) [ |
             val transformer = generatedClasses.get(inputType);
             if (transformer != null) {
@@ -111,7 +119,7 @@ class TransformerGenerator {
 
     }
 
-    def Class<?> getValueSerializer(GeneratedTransferObject type) {
+    private def Class<?> getValueSerializer(GeneratedTransferObject type) {
         val cls = loadClassWithTCCL(type.resolvedName);
         val transformer = generatedClasses.get(cls);
         if (transformer !== null) {
@@ -170,18 +178,16 @@ class TransformerGenerator {
                     '''
                 ]
             ]
-            val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
             log.info("DOM Codec for {} was generated {}",inputType,ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
-            val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
-            exception.addSuppressed(e);
-            throw exception;
+            processException(inputType,e);
+            return null;
         }
     }
 
-    private def <D> Class<? extends BindingCodec<Map<QName, Object>, D>> generateTransformerFor(Class<D> inputType,
+    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(Class inputType,
         GeneratedType typeSpec, SchemaNode node) {
         try {
             log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
@@ -209,15 +215,55 @@ class TransformerGenerator {
                 ]
             ]
 
-            val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
-            return ret as Class<? extends BindingCodec<Map<QName,Object>, D>>;
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
-            val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
-            exception.addSuppressed(e);
-            throw exception;
+            processException(inputType,e);
+            return null;
         }
     }
+    
+    
+    private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(Class inputType,
+        GeneratedType typeSpec, ChoiceNode node) {
+        try {
+            log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
+            val ctCls = createClass(typeSpec.transformatorFqn) [
+                //staticField(Map,"AUGMENTATION_SERIALIZERS");
+                //staticQNameField(inputType);
+                implementsType(ctTransformator)
+                method(Object, "toDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        return null;
+                    '''
+                ]
+                method(Object, "serialize", Object) [
+                    body = '''
+                        return null;
+                    '''
+                ]
+                method(Object, "fromDomStatic", QName, Object) [
+                    modifiers = PUBLIC + FINAL + STATIC
+                    body = '''
+                        return null;
+                    '''
+                ]
+                method(Object, "deserialize", Object) [
+                    body = '''
+                        return null;
+                    '''
+                ]
+            ]
+
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+            return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        } catch (Exception e) {
+            processException(inputType,e);
+            return null;
+        }
+    }
+    
 
     private def keyConstructorList(List<QName> qnames) {
         val names = new TreeSet<String>()
@@ -309,7 +355,7 @@ class TransformerGenerator {
         DataNodeContainer node) {
         val ret = '''
             «FOR child : node.childNodes.filter[!augmenting]»
-                «val signature = properties.get(child.getterName
+                «val signature = properties.getFor(child
                 «deserializeProperty(child, signature.returnType, signature)»
                 _builder.«signature.name.toSetter»(«signature.name»);
             «ENDFOR»
@@ -396,7 +442,7 @@ class TransformerGenerator {
             if (returnType == null) {
 
                 val ctCls = createDummyImplementation(inputType, typeSpec);
-                val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
+                val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
             }
             val ctCls = createClass(typeSpec.transformatorFqn) [
@@ -436,7 +482,7 @@ class TransformerGenerator {
                             if($1 == null) {
                                 return null;
                             }
-                            «returnType.name» _simpleValue = «deserializeValue(returnType, "$1")»;
+                            «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1")»;
                             «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue);
                             return _value;
                         }
@@ -450,12 +496,12 @@ class TransformerGenerator {
                 ]
             ]
 
-            val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
             log.info("DOM Codec for {} was generated {}",inputType,ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
-            val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
+            log.error("Cannot compile DOM Codec for {}",inputType,e);
+            val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
             exception.addSuppressed(e);
             throw exception;
         }
@@ -492,7 +538,7 @@ class TransformerGenerator {
         ]
     }
 
-    def Type getValueReturnType(GeneratedTransferObject object) {
+    private def Type getValueReturnType(GeneratedTransferObject object) {
         for (prop : object.properties) {
             if (prop.name == "value") {
                 return prop.returnType;
@@ -544,16 +590,35 @@ class TransformerGenerator {
                 ]
             ]
 
-            val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
+            val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
             log.info("DOM Codec for {} was generated {}",inputType,ret)
             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        } catch (CodeGenerationException e) {
+            throw new CodeGenerationException("Cannot compile Transformator for " + inputType,e);
         } catch (Exception e) {
-            log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
-            val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
+            log.error("Cannot compile DOM Codec for {}",inputType,e);
+            val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
             exception.addSuppressed(e);
             throw exception;
         }
 
+    }
+    
+    def Class<?> toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) {
+        val cls = newClass.toClass(loader,domain);
+        if(classFileCapturePath !== null) {
+            newClass.writeFile(classFileCapturePath.absolutePath);
+        }
+        return cls;
+    }
+    
+    def debugWriteClass(CtClass class1) {
+        val path = class1.name.replace(".","/")+".class"
+        
+        val captureFile = new File(classFileCapturePath,path);
+        captureFile.createNewFile
+        
+        
     }
 
     private def dispatch String deserializeValue(Type type, String domParameter) '''(«type.resolvedName») «domParameter»'''
@@ -624,15 +689,47 @@ class TransformerGenerator {
         }
     '''
 
+    private def dispatch String serializeBody(GeneratedType type, ChoiceCaseNode node) '''
+        {
+        «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
+            java.util.List childNodes = new java.util.ArrayList();
+            «type.resolvedName» value = («type.resolvedName») $2;
+            «transformDataContainerBody(type.allProperties, node)»
+            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+        }
+    '''
+
+    private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
+        {
+        «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
+            java.util.List childNodes = new java.util.ArrayList();
+            «type.resolvedName» value = («type.resolvedName») $2;
+            return ($r) java.util.Collections.singletonMap(resultName,childNodes);
+        }
+    '''
+
+
     private def transformDataContainerBody(Map<String, MethodSignature> properties, DataNodeContainer node) {
         val ret = '''
             «FOR child : node.childNodes.filter[!augmenting]»
-                «val signature = properties.get(child.getterName
+                «var signature = properties.getFor(child
                 «serializeProperty(child, signature.returnType, signature)»
             «ENDFOR»
         '''
         return ret;
     }
+    
+    def MethodSignature getFor(Map<String,MethodSignature> map, DataSchemaNode node) {
+        val sig = map.get(node.getterName);
+        if(sig == null) {
+            return map.get(node.booleanGetterName);
+        }
+        return sig;
+    }
+
+    private static def String getBooleanGetterName(DataSchemaNode node) {
+        return "is" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
+    }
 
     private static def String getGetterName(DataSchemaNode node) {
         return "get" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
@@ -711,16 +808,12 @@ class TransformerGenerator {
         MethodSignature property) '''
         «property.returnType.resolvedName» «property.name» = value.«property.name»();
         if(«property.name» != null) {
-            Object domValue = «type.serializer».toDomStatic(QNAME,«property.name»);
+            Object domValue = «type.serializer.name».toDomStatic(QNAME,«property.name»);
             childNodes.add(domValue);
         }
     '''
 
-    private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
-        {
-            return ($r) java.util.Collections.singletonMap(this.QNAME,null);
-        }
-    '''
+
 
     private def transformatorFqn(GeneratedType typeSpec) {
         return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
@@ -759,6 +852,19 @@ class TransformerGenerator {
         val cls = loadClassWithTCCL(type.fullyQualifiedName)
         return cls.asCtClass;
     }
+    
+    
+    
+    private def dispatch processException(Class<?> inputType,CodeGenerationException e){
+        log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.",inputType);
+        throw e;
+    }
+    
+    private def dispatch processException(Class<?> inputType,Exception e){
+        log.error("Cannot compile DOM Codec for {}",inputType,e);
+        val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType,e);
+        throw exception;
+    }
 
 }
 
index e2b79203c94dd6db2bb33026dd2ba804b08857a1..a0e1c98237ed0e963a1a3982874f46bbaca463f9 100644 (file)
@@ -55,8 +55,6 @@ import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
 
 class BindingMapping {
 
-
-
     @Property
     val Map<Type, GeneratedTypeBuilder> typeToDefinition = new HashMap();
     
index 0b91658a187399758e5e8dac99f884749c0d048e..87f31ac5c435820c5ddb5ec505e3dabbab94eba8 100644 (file)
@@ -34,6 +34,10 @@ public class ClassLoaderUtils {
     
     
     public static Class<?> loadClassWithTCCL(String name) throws ClassNotFoundException {
+        if("byte[]".equals(name)) {
+            return byte[].class;
+        }
+        
         return Thread.currentThread().getContextClassLoader().loadClass(name);
     }
 }
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
new file mode 100644 (file)
index 0000000..27d985b
--- /dev/null
@@ -0,0 +1,107 @@
+package org.opendaylight.controller.sal.binding.test;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.controller.sal.binding.test.connect.dom.MappingServiceTest;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.reflections.Reflections;
+import org.reflections.scanners.ResourcesScanner;
+
+import com.google.common.base.Predicate;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public  abstract class AbstractDataServiceTest {
+    protected DataBrokerService biDataService;
+    protected DataProviderService baDataService;
+    
+    protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+    protected BindingIndependentMappingService mappingService;
+    protected DataBrokerImpl baDataImpl;
+    protected org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
+    protected ListeningExecutorService executor;
+    protected BindingIndependentDataServiceConnector connectorServiceImpl;
+    protected HashMapDataStore dataStore;
+    
+    
+    @Before
+    public void setUp() {
+        executor = MoreExecutors.sameThreadExecutor();
+        baDataImpl = new DataBrokerImpl();
+        baDataService = baDataImpl;
+        baDataImpl.setExecutor(executor);
+        
+        biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
+        biDataService =  biDataImpl;
+        biDataImpl.setExecutor(executor);
+        
+        dataStore = new HashMapDataStore();
+        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().toInstance();
+        biDataImpl.registerConfigurationReader(treeRoot, dataStore);
+        biDataImpl.registerOperationalReader(treeRoot, dataStore);
+        biDataImpl.registerCommitHandler(treeRoot, dataStore);
+        
+        mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
+        mappingService = mappingServiceImpl;
+        File pathname = new File("target/gen-classes-debug");
+        //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath());
+        mappingServiceImpl.start();
+        //mappingServiceImpl.getBinding().setClassFileCapturePath(pathname);
+        
+        connectorServiceImpl = new BindingIndependentDataServiceConnector();
+        connectorServiceImpl.setBaDataService(baDataService);
+        connectorServiceImpl.setBiDataService(biDataService);
+        connectorServiceImpl.setMappingService(mappingServiceImpl);
+        connectorServiceImpl.start();
+        
+        String[] yangFiles= getModelFilenames();
+        mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles));
+    }
+
+
+    protected  String[] getModelFilenames() {
+        return getModelFilenamesImpl();
+    }
+    
+    public static String[] getModelFilenamesImpl() {
+        Predicate<String> predicate = new Predicate<String>() {
+            @Override
+            public boolean apply(String input) {
+                return input.endsWith(".yang");
+            }
+        };
+        Reflections reflection= new Reflections("META-INF.yang", new ResourcesScanner());
+        Set<String> result = reflection.getResources(predicate);
+        return (String[]) result.toArray(new String[result.size()]);
+    }
+    
+    public static SchemaContext getContext(String[] yangFiles) {
+
+        ClassLoader loader = AbstractDataServiceTest.class.getClassLoader();
+
+        List<InputStream> streams = new ArrayList<>();
+        for (String string : yangFiles) {
+            InputStream stream = loader.getResourceAsStream(string);
+            streams.add(stream);
+
+        }
+        YangParserImpl parser = new YangParserImpl();
+
+        Set<Module> modules = parser.parseYangModelsFromStreams(streams);
+        return parser.resolveSchemaContext(modules);
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java
new file mode 100644 (file)
index 0000000..70be175
--- /dev/null
@@ -0,0 +1,144 @@
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+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 com.google.common.collect.ImmutableMap;
+
+import static org.junit.Assert.*;
+
+/**
+ * 
+ * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id=144
+ * 
+ * Cannot compile CoDec for org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
+ * 
+ * @author ttkacik
+ *
+ */
+public class DOMCodecBug01Test extends AbstractDataServiceTest {
+
+    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
+    private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node");
+    
+    private static final String FLOW_ID = "foo";
+    private static final String NODE_ID = "node:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder().node(Nodes.class)
+            .node(Node.class, NODE_KEY).toInstance();
+    
+    
+    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+            NODE_ID);
+    
+    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 NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
+    
+    private static final FlowKey FLOW_KEY = new FlowKey(FLOW_ID, NODE_REF);
+
+    private static final Map<QName, Object> FLOW_KEY_BI = //
+            ImmutableMap.<QName,Object>of(FLOW_ID_QNAME, FLOW_ID, FLOW_NODE_QNAME, NODE_REF);
+
+
+    
+
+    private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = //
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+                    .node(Flows.QNAME) //
+                    .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
+                    .toInstance();
+    private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
+            InstanceIdentifier.builder() //
+                .node(Flows.class) //
+                .node(Flow.class, FLOW_KEY) //
+                .toInstance();
+    /**
+     * 
+     * When invoking following code in the consumer, user got an
+     * IllegalStateException during creation of mapping between Java DTOs and
+     * data-dom.
+     * 
+     * Exception was compilation error which was caused by incorect generation
+     * of code.
+     * 
+     * 
+     */
+    @Test
+    public void testIndirectGeneration() throws Exception {
+
+        DataModificationTransaction modification = baDataService.beginTransaction();
+
+       FlowBuilder flow = new FlowBuilder();
+        MatchBuilder match = new MatchBuilder();
+        VlanMatchBuilder vlanBuilder = new VlanMatchBuilder();
+        VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
+        VlanId vlanId = new VlanId(10);
+        vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build());
+        match.setVlanMatch(vlanBuilder.build());
+
+        flow.setKey(FLOW_KEY);
+        flow.setMatch(match.build());
+        flow.setNode(NODE_REF);
+
+        modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build());
+        RpcResult<TransactionStatus> ret = modification.commit().get();
+        assertNotNull(ret);
+        assertEquals(TransactionStatus.COMMITED, ret.getResult());
+        
+        verifyDataAreStoredProperly();
+        
+        
+        DataModificationTransaction modification2 = baDataService.beginTransaction();
+        modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA);
+        
+        DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA);
+        assertNotNull(originalData);
+        RpcResult<TransactionStatus> ret2 = modification2.commit().get();
+        
+        assertNotNull(ret2);
+        assertEquals(TransactionStatus.COMMITED, ret2.getResult());
+        
+        
+        // Data are not in the store.
+        assertNull(baDataService.readOperationalData(FLOW_INSTANCE_ID_BA));
+        
+        
+    }
+
+    private void verifyDataAreStoredProperly() {
+        CompositeNode biFlow = biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI);
+        assertNotNull(biFlow);
+        CompositeNode biMatch = biFlow.getFirstCompositeByName(QName.create(Flow.QNAME,Match.QNAME.getLocalName()));
+        assertNotNull(biMatch);
+    }
+}
index 0e35ee650e91041a592d6526a186bb9d4580fab3..7706cda750bd342555da2a95dc5b4e635daf6099 100644 (file)
@@ -4,21 +4,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
-import java.util.concurrent.Executors;
+
 import java.util.concurrent.Future;
 
-import org.junit.Before;
+
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.RuntimeGeneratedMappingServiceImpl;
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
@@ -29,139 +24,87 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-public class BrokerIntegrationTest {
-
-    DataBrokerService biDataService;
-    DataProviderService baDataService;
-    private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
-    private BindingIndependentMappingService mappingService;
-    private DataBrokerImpl baDataImpl;
-    private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
-    private ListeningExecutorService executor;
-    private BindingIndependentDataServiceConnector connectorServiceImpl;
-    private HashMapDataStore dataStore;
-    
-    
-    @Before
-    public void setUp() {
-        executor = MoreExecutors.sameThreadExecutor();
-        baDataImpl = new DataBrokerImpl();
-        baDataService = baDataImpl;
-        baDataImpl.setExecutor(executor);
-        
-        biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
-        biDataService =  biDataImpl;
-        biDataImpl.setExecutor(executor);
-        
-        dataStore = new HashMapDataStore();
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().toInstance();
-        biDataImpl.registerConfigurationReader(treeRoot, dataStore);
-        biDataImpl.registerOperationalReader(treeRoot, dataStore);
-        biDataImpl.registerCommitHandler(treeRoot, dataStore);
-        
-        mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
-        mappingService = mappingServiceImpl;
-        mappingServiceImpl.start();
-        
-        connectorServiceImpl = new BindingIndependentDataServiceConnector();
-        connectorServiceImpl.setBaDataService(baDataService);
-        connectorServiceImpl.setBiDataService(biDataService);
-        connectorServiceImpl.setMappingService(mappingServiceImpl);
-        connectorServiceImpl.start();
-        
-        String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang",
-        "node-inventory.yang" };
-        
-        mappingServiceImpl.onGlobalContextUpdated(MappingServiceTest.getContext(yangFiles));
-        
-    }
-    
+public class BrokerIntegrationTest extends AbstractDataServiceTest {
+
     @Test
     public void simpleModifyOperation() throws Exception {
-        
-        
+
         NodeRef node1 = createNodeRef("0");
-        DataObject  node = baDataService.readConfigurationData(node1.getValue());
+        DataObject node = baDataService.readConfigurationData(node1.getValue());
         assertNull(node);
         Node nodeData1 = createNode("0");
-        
-        
+
         DataModificationTransaction transaction = baDataService.beginTransaction();
         transaction.putConfigurationData(node1.getValue(), nodeData1);
         Future<RpcResult<TransactionStatus>> commitResult = transaction.commit();
         assertNotNull(commitResult);
-        
+
         RpcResult<TransactionStatus> result = commitResult.get();
-        
+
         assertNotNull(result);
         assertNotNull(result.getResult());
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
+
         Node readedData = (Node) baDataService.readConfigurationData(node1.getValue());
         assertNotNull(readedData);
         assertEquals(nodeData1.getKey(), readedData.getKey());
-        
-        
+
         NodeRef nodeFoo = createNodeRef("foo");
         NodeRef nodeBar = createNodeRef("bar");
         Node nodeFooData = createNode("foo");
         Node nodeBarData = createNode("bar");
-        
-        
+
         DataModificationTransaction insertMoreTr = baDataService.beginTransaction();
         insertMoreTr.putConfigurationData(nodeFoo.getValue(), nodeFooData);
         insertMoreTr.putConfigurationData(nodeBar.getValue(), nodeBarData);
         RpcResult<TransactionStatus> result2 = insertMoreTr.commit().get();
-        
+
         assertNotNull(result2);
         assertNotNull(result2.getResult());
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
-        Nodes allNodes = (Nodes) baDataService.readConfigurationData(InstanceIdentifier.builder().node(Nodes.class).toInstance());
+
+        Nodes allNodes = (Nodes) baDataService.readConfigurationData(InstanceIdentifier.builder().node(Nodes.class)
+                .toInstance());
         assertNotNull(allNodes);
         assertNotNull(allNodes.getNode());
         assertEquals(3, allNodes.getNode().size());
-        
-        
+
         /**
          * We create transaction no 2
          * 
          */
         DataModificationTransaction removalTransaction = baDataService.beginTransaction();
         assertNotNull(transaction);
-        
+
         /**
          * We remove node 1
          * 
          */
         removalTransaction.removeConfigurationData(node1.getValue());
-        
+
         /**
          * We commit transaction
          */
         Future<RpcResult<TransactionStatus>> commitResult2 = removalTransaction.commit();
         assertNotNull(commitResult2);
-        
+
         RpcResult<TransactionStatus> result3 = commitResult2.get();
-        
+
         assertNotNull(result3);
         assertNotNull(result3.getResult());
         assertEquals(TransactionStatus.COMMITED, result2.getResult());
-    
+
         DataObject readedData2 = baDataService.readConfigurationData(node1.getValue());
         assertNull(readedData2);
     }
-    
+
     private static NodeRef createNodeRef(String string) {
         NodeKey key = new NodeKey(new NodeId(string));
         InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
                 .toInstance();
         return new NodeRef(path);
     }
-    
+
     private static Node createNode(String string) {
         NodeBuilder ret = new NodeBuilder();
         ret.setId(new NodeId(string));
index b0c2e7529ad1edcfd2e8e18104c6613a0e1a227a..e26273e026cf6d098d6e7efb38ef2dd176c9d1e5 100644 (file)
@@ -17,6 +17,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.MappingServiceImpl;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 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.NodesBuilder;
@@ -48,10 +49,9 @@ public class MappingServiceTest {
     @Test
     public void baDataToBiData() throws Exception {
 
-        String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang",
-                "node-inventory.yang" };
+        String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl();
 
-        SchemaContext ctx = getContext(yangFiles);
+        SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles);
 
         impl.onGlobalContextUpdated(ctx);
 
@@ -73,9 +73,8 @@ public class MappingServiceTest {
     @Test
     public void instanceIdentifierTest() throws Exception {
 
-        String[] yangFiles = new String[] { "yang-ext.yang", "ietf-inet-types.yang", "ietf-yang-types.yang",
-                "node-inventory.yang" };
-        SchemaContext ctx = getContext(yangFiles);
+        String[] yangFiles = AbstractDataServiceTest.getModelFilenamesImpl();
+        SchemaContext ctx = AbstractDataServiceTest.getContext(yangFiles);
         impl.onGlobalContextUpdated(ctx);
 
         NodeKey nodeKey = new NodeKey(new NodeId("foo"));
@@ -85,22 +84,6 @@ public class MappingServiceTest {
         assertEquals(2, result.getPath().size());
     }
 
-    public static SchemaContext getContext(String[] yangFiles) {
-
-        ClassLoader loader = MappingServiceTest.class.getClassLoader();
-
-        List<InputStream> streams = new ArrayList<>();
-        for (String string : yangFiles) {
-            InputStream stream = loader.getResourceAsStream("META-INF/yang/" + string);
-            streams.add(stream);
-
-        }
-        YangParserImpl parser = new YangParserImpl();
-
-        Set<Module> modules = parser.parseYangModelsFromStreams(streams);
-        return parser.resolveSchemaContext(modules);
-    }
-
     private Node createChildNode(String id) {
         NodeBuilder node = new NodeBuilder();
         NodeId nodeId = new NodeId(id);