From 8b5959e7389215bc106e59f7c3f8402ace363a22 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Thu, 14 Nov 2013 20:07:29 +0100 Subject: [PATCH] Fix for Bug 144 - 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 --- .../md-sal/sal-binding-broker/pom.xml | 12 ++ .../codegen/CodeGenerationException.java | 25 +++ .../impl/TransformerGenerator.xtend | 168 ++++++++++++++---- .../impl/connect/dom/BindingMapping.xtend | 2 - .../binding/impl/util/ClassLoaderUtils.java | 4 + .../binding/test/AbstractDataServiceTest.java | 107 +++++++++++ .../test/bugfix/DOMCodecBug01Test.java | 144 +++++++++++++++ .../connect/dom/BrokerIntegrationTest.java | 111 +++--------- .../test/connect/dom/MappingServiceTest.java | 27 +-- 9 files changed, 461 insertions(+), 139 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/CodeGenerationException.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index 9e4d3a580c..c356ff6b0e 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -218,6 +218,12 @@ 1.0-SNAPSHOT test + + org.opendaylight.controller.model + model-flow-management + 1.0-SNAPSHOT + test + org.opendaylight.yangtools yang-data-impl @@ -234,5 +240,11 @@ ${slf4j.version} test + + org.reflections + reflections + 0.9.9-RC1 + test + 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 index 0000000000..1923040726 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/CodeGenerationException.java @@ -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); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend index 2d67f11eb2..2136572aa3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend @@ -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 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, ?>>; } 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 Class, D>> generateTransformerFor(Class inputType, + private def dispatch Class, 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, D>>; + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + return ret as Class, 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, 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, Object>>; + } catch (Exception e) { + processException(inputType,e); + return null; + } + } + private def keyConstructorList(List qnames) { val names = new TreeSet() @@ -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, 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, 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, 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 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 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; + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend index e2b79203c9..a0e1c98237 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingMapping.xtend @@ -55,8 +55,6 @@ import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature class BindingMapping { - - @Property val Map typeToDefinition = new HashMap(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java index 0b91658a18..87f31ac5c4 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java @@ -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 index 0000000000..27d985b2d2 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -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 predicate = new Predicate() { + @Override + public boolean apply(String input) { + return input.endsWith(".yang"); + } + }; + Reflections reflection= new Reflections("META-INF.yang", new ResourcesScanner()); + Set result = reflection.getResources(predicate); + return (String[]) result.toArray(new String[result.size()]); + } + + public static SchemaContext getContext(String[] yangFiles) { + + ClassLoader loader = AbstractDataServiceTest.class.getClassLoader(); + + List streams = new ArrayList<>(); + for (String string : yangFiles) { + InputStream stream = loader.getResourceAsStream(string); + streams.add(stream); + + } + YangParserImpl parser = new YangParserImpl(); + + Set 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 index 0000000000..70be175598 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java @@ -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_INSTANCE_ID_BA = InstanceIdentifier.builder().node(Nodes.class) + .node(Node.class, NODE_KEY).toInstance(); + + + private static final Map NODE_KEY_BI = Collections. 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 FLOW_KEY_BI = // + ImmutableMap.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 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 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 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); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java index 0e35ee650e..7706cda750 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java @@ -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> commitResult = transaction.commit(); assertNotNull(commitResult); - + RpcResult 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 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> commitResult2 = removalTransaction.commit(); assertNotNull(commitResult2); - + RpcResult 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 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)); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java index b0c2e7529a..e26273e026 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MappingServiceTest.java @@ -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 streams = new ArrayList<>(); - for (String string : yangFiles) { - InputStream stream = loader.getResourceAsStream("META-INF/yang/" + string); - streams.add(stream); - - } - YangParserImpl parser = new YangParserImpl(); - - Set modules = parser.parseYangModelsFromStreams(streams); - return parser.resolveSchemaContext(modules); - } - private Node createChildNode(String id) { NodeBuilder node = new NodeBuilder(); NodeId nodeId = new NodeId(id); -- 2.36.6