From af7ad35c9f574ca6ecbf18c505d3112aea2f58ac Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Mon, 2 Dec 2013 12:46:22 +0100 Subject: [PATCH] Fixed serialization of InstanceIdentifier's which contains Augmentation in path. Change-Id: I0ef71ec04eaa14f95fc0f4857254eef506d78bb4 Signed-off-by: Tony Tkacik --- .../dom/serializer/api/CodecRegistry.java | 2 + .../dom/serializer/impl/CodecMapping.java | 2 +- .../serializer/impl/GeneratorListener.java | 7 +- .../impl/InstanceIdentifierCodecImpl.xtend | 46 ++++++++-- .../impl/LazyGeneratedCodecRegistry.java | 91 +++++++++++++------ .../RuntimeGeneratedMappingServiceImpl.xtend | 32 +++++-- .../impl/TransformerGenerator.xtend | 65 ++++++++++--- .../sal/binding/impl/DataBrokerImpl.java | 19 +++- ...indingIndependentDataServiceConnector.java | 7 +- .../binding/impl/util/ClassLoaderUtils.java | 9 ++ .../binding/impl/util/YangSchemaUtils.java | 26 ++++++ .../test/bugfix/DOMCodecBug03Test.java | 62 +++++++++++-- 12 files changed, 298 insertions(+), 70 deletions(-) diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java index 1a02ea17e4..a31d3eedd2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/api/CodecRegistry.java @@ -29,4 +29,6 @@ public interface CodecRegistry { void bindingClassEncountered(Class cls); + + void putPathToClass(List names, Class cls); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java index 79a11ce278..172fb05292 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/CodecMapping.java @@ -59,7 +59,7 @@ public class CodecMapping { } } - public static void setAugmentationCodec(Class, Object>> dataCodec, + public static void setAugmentationCodec(Class> dataCodec, BindingCodec augmentableCodec) { Field instanceIdField; try { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java index 0a8ea84cf6..0ac239d505 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/GeneratorListener.java @@ -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,Object>> choiceCodec); void onCaseCodecCreated(Class choiceClass,Class,Object>> choiceCodec); - public abstract void onDataContainerCodecCreated(Class dataClass, Class,Object>> dataCodec); + void onDataContainerCodecCreated(Class dataClass, Class> dataCodec); + + void onChoiceCodecCreated(Class choiceClass, + Class, Object>> choiceCodec, ChoiceNode schema); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend index 2706609806..150d0f199f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/InstanceIdentifierCodecImpl.xtend @@ -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,QName> classToQName = new WeakHashMap; - + val Map, Map, 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; + if(augment != null) { + baArgs.add(new Item(augment)); + } + } + baArgs.add(baArg) } val ret = new InstanceIdentifier(baArgs,baType as Class); return ret; @@ -74,18 +85,41 @@ class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { } override serialize(InstanceIdentifier input) { + var Class previousAugmentation = null val pathArgs = input.path as List var QName previousQName = null; val components = new ArrayList(pathArgs.size); + val qnamePath = new ArrayList(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 class1, ImmutableList 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); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index 961cb2eb59..de6836489e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -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 pathToType = new ConcurrentHashMap<>(); + Map, Type> pathToInstantiatedType = new ConcurrentHashMap<>(); private SchemaContext currentSchema; @@ -116,15 +123,27 @@ public class LazyGeneratedCodecRegistry implements // public Class getClassForPath(List 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 weakRef = typeToClass.get(typeref); - if(weakRef == null) { - LOG.error("Could not find loaded class for path: {} and type: {}",path,typeref.getFullyQualifiedName()); + WeakReference 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 names,Class cls) { + Type reference = Types.typeForClass(cls); + pathToInstantiatedType.put(names, reference ); + bindingClassEncountered(cls); + } + @Override public IdentifierCodec getKeyCodecForPath(List 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 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) 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 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, Object>> choiceCodec) { + Class, Object>> choiceCodec, ChoiceNode schema) { ChoiceCodec oldCodec = choiceCodecs.get(choiceClass); checkState(oldCodec == null); BindingCodec, Object> delegate = newInstanceOf(choiceCodec); @@ -331,6 +352,22 @@ public class LazyGeneratedCodecRegistry implements // choiceCodecs.put(choiceClass, newCodec); CodecMapping.setClassToCaseMap(choiceCodec, (Map, 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, Object>> dataCodec) { + Class> 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, Object> put(T key, BindingCodec value) { + public BindingCodec, Object> put(T key, BindingCodec value) { throw notModifiable(); } @@ -705,9 +742,9 @@ public class LazyGeneratedCodecRegistry implements // augmentationField.setAccessible(true); Map augMap = (Map) 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; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend index 0da7aec480..7eb473ce34 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -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 class1) { + private def void waitForSchema(Class 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(); } 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 ab2e96f05c..a732f152b2 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 @@ -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 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> + listener?.onDataContainerCodecCreated(inputType,ret); log.info("DOM Codec for {} was generated {}", inputType, ret) - return ret as Class>; + 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, 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, 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»)''' diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java index 02c59b2779..5db522f56c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java @@ -1,8 +1,9 @@ package org.opendaylight.controller.sal.binding.impl; +import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; - + import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; @@ -99,5 +100,21 @@ public class DataBrokerImpl extends AbstractDataBroker key, + Set> paths) { + if (paths.contains(key)) { + return true; + } + for (InstanceIdentifier path : paths) { + if (key.containsWildcarded(path)) { + return true; + } + } + + return false; } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java index 864c048a91..5f3189f7d2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java @@ -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 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. } 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 cb3206a3b3..596329e07b 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 @@ -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 diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/YangSchemaUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/YangSchemaUtils.java index b7a21cb022..1426089360 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/YangSchemaUtils.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/YangSchemaUtils.java @@ -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 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; + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java index 91163d80f2..d3ef2f3d6e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java @@ -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_INSTANCE_ID_BA = InstanceIdentifier.builder(NODES_INSTANCE_ID_BA) // + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier// + .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY).toInstance(); + + + private static final InstanceIdentifier 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, 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 actionTypes = Collections.singletonList(action.build()); + actions.setActionType(actionTypes ); + transaction.putOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA, actions.build()); + RpcResult 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 { -- 2.36.6